[so] [Indicatii generale teme]Definitii de functii non-statice in headere

Vlad Dogaru ddvlad at herebedragons.ro
Mon Feb 25 18:19:49 EET 2013


On Mon, Feb 25, 2013 at 03:37:25PM +0000, Mihail-Daniel STĂNCIULESCU wrote:
> Salut,
> 
> In lista de depunctari pentru teme exista un punct unde scrie ca
> definitiile de functii non statice in headere sunt depunctate. 
> * Imi puteti explica va rog ce inseamna acest lucru deoarece nu gasesc
> nici un exemplu in acest sens in alte articole de coding style?
> * Unde putem defini functiile non-statice astfel incat sa nu duplicam
> codul lor in fiecare fisier in care sunt folosite?
> * In headerele de C din sistem am gasit ca functiile sunt definite cu
> extern. La acest lucru se refera punctul din lista de depunctari?

(1)

Dacă definești asta într-un header:

	/* În foo.h */
	int foo(int x)
	{
		return 0;
	}

și acel header este inclus de două fișiere sursă, ambele fișiere obiect
(.o) rezultate din compilare vor conține cod pentru funcția foo.

Dacă cele două obiecte sunt link-editate împreună, linker-ul dă cu
eroare, pentru că există două simboluri cu același nume:

	/tmp/ccAWkbPI.o: In function `foo':
	bar.c:(.text+0x0): multiple definition of `foo'
	/tmp/ccpwlOcl.o:foo.c:(.text+0x0): first defined here
	collect2: error: ld returned 1 exit status

***

(2)

Ce _vrei_, de fapt, să faci, e să declari funcția ca extern în header
(în cazul ăsta, extern e opțional):

	/* În foo.h */
	extern int foo(int x);

În unul dintre fișierele sursă C implementezi funcția:

	/* În foo.c */
	int foo(int x)
	{
		return 0;
	}

Și în celălalt fișier incluzi header-ul, care spune că există funcția,
dar nu dă și implementarea ei:

	/* În bar.c */
	#include "foo.h"
	/* ... */
	printf("%d\n", foo(0));

La compilare, simbolul foo va fi unresolved în bar.o, dar asta e ok,
pentru că va fi rezolvat de linker în etapa de link-editare -- va fi
folosit simbolul din foo.o.

***

(3)

O variantă mai puțin tipică (dar foarte utilă) e folosită, printre
altele, de kernel-ul Linux:

Dacă vrei să ai o funcție inline (din rațiuni de performanță), ea
trebuie să fie prezentă în sursa curentă, pentru că nu linker-ul, ci
compilatorul, face inlining.  Or, în varianta prezentată mai sus,
compilatorul nu are sursa lui foo în bar.c și nu poate face inlining.

Soluția este să îl declarăm pe foo în header, _dar_ acesta trebuie să
fie static:

	/* În foo.h */
	static inline int foo(int x)
	{
		return 0;
	}

Cuvântul cheie static înseamnă că simbolul foo nu va fi exportat de
modul, deci linker-ul nu se va plânge că există două foo-uri.

Două referințe utile:
[1] http://stackoverflow.com/questions/4576607/static-keyword-in-ansi-c
[2] http://kernel.org/doc/local/inline.html

***

Concluzie:

Tu vrei, de obicei, varianta (2).  Varianta (1) este incorectă, iar (3)
este o optimizare.

Guideline-ul este formulat astfel încât sunt permise (2) și (3), dar nu
și (1).  De-asta pomenește de funcții non-statice în headere.

Hope this helps,
Vlad


More information about the so mailing list