Az -fno-common-nal kapcsolatban: őszintén szólva nem értem, hogy miért nem az -fno-common az alapértelmezett beállítás. Ugyanis az -fcommon definiál egy olyan viselkedést, ami a C szabvány szerint definitálatlan -- és ez minimum zavaró. Például:
// a.c
int x;
int main(void) { return x; }
// b.c
int x;
Bármelyik file-t önmagában tekintve az int x; deklaráció tentative definition (kísérleti definíció), amely a file végét elérve external definition-né (külső definícióvá) válik. Ugyanis idézzük pl. a C99 szabványt (6.9.2 External object definitions, 2. bekezdés):
A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier
static, constitutes a tentative definition. If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.
Más szóval a szabvány a két fenti forrásfile viselkedését úgy szabja meg, hogy az egyenrangú legyen a következőkkel:
// a2.c
int x = 0;
int main(void) { return x; }
// b2.c
int x = 0;
Ezek viszont már (külön-külön) external definition-nek számítanak (6.9.2 External object definitions, 1. bekezdés)::
If the declaration of an identifier for an object has file scope and an initializer, the declaration is an external definition for the identifier.
Továbbá az x változónak mindkét file-ban (és mindkét változatban) external linkage-e van (6.2.2 Linkages of identifiers, 5. bekezdés 2. mondat):
[...] If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.
A két eredeti forrásfile-t egyetlen programba összelinkelve pedig megszegnénk a szabványt (6.9 External definitions, 5. bekezdés 2. mondat; aláhúzásos kiemelés tőlem):
[...] If an identifier declared with external linkage is used in an expression (other than as part of the operand of a
sizeofoperator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier [...]
És akkor nézzük meg pl. a gcc viselkedését:
gcc -std=c99 -Wall -Wextra -pedantic a.c b.c
A parancs nem jelez hibát. Itt jön a képbe az, hogy a shall hogyan értelmezendő:
- 4. Conformance, 1. és 2. bekezdésekből:
In this International Standard, ‘‘shall’’ is to be interpreted as a requirement on an implementation or on a program [...]
If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a constraint is violated, the behavior is undefined. [...] - 5.1.1.3 Diagnostics, 1. bekezdés 1. mondat:
A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined. [...]
A gcc-re csak azért nem mondhatjuk, hogy megszegi a szabványt, met a 6.9 External definitions, 5. bekezdés -- amely a "pontosan egy külső definíció" előírást tartalmazza -- nem egy Constraints szakaszban található, hanem egy Semantics szakaszban. Az előbbi esetben a gcc viselkedése megszegné a szabványt, így viszont csak az a helyzet, hogy a gcc definiál egy olyan viselkedést, amelyet a szabvány nem definiál. Ennek ellenére a gcc működése szerintem nagyon zavaró.
És akkor az -fno-common kapcsolóval ugyanez:
gcc -std=c99 -Wall -Wextra -pedantic -fno-common a.c b.c
Itt már van hibaüzenet:
/tmp/cc96ba6O.o:(.bss+0x0): multiple definition of `x'
/tmp/ccL5BbT8.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
Csak hogy három projektet említsek, amivel dolgom volt: mind az edk2, mind a qemu, mind a libvirt projektek megadják az -fno-common-t. Szerintem állíthatjuk azt, hogy az -fcommon mint alapértelmezés hiba (vagy minimum tévedés) a fordítókban.