extern const initialized warns in C

Jay K jayk123@hotmail.com
Mon Jan 22 10:25:00 GMT 2018


> I find the "scoping" too hard to pass it, and if I need to make
>     the symbol extern in future, I can afford a rename to do it.


I mean, I actually like like the ability to shorten file level static symbols.


As you point out, true, you can have it both ways, static does not force shortening, merely allows it, and protects you from inadvertant duplication.


Really, the prohibition against file level static is used in large code bases.

You already have to chose unique extern names, and depend on the linker to diagnose duplicate externals for them.

Extending this by barring statics isn't necessarily significant.

Such code bases prefix every extern identifier with some "local" prefix, and any missing prefix is easy to spot and a stylistic mistake.

(i.e. local to the subsystem or directory -- I realize it is the very definition of "local" that makes or break this)


I understand that hiding by omission from headers is not hiding at the linker level.


I agree there are scalability problems with naming in C, but it isn't clear static helps significantly.


There is an interesting side effect though that I think is not very much appreciated.

Large C code bases are more amenable to plain text search than large C++ code bases, due to the "more uniqueness" of symbols.


This plain text search aspect is one of extremely few advantages I see to C over C++, perhaps the only one.


 - Jay


________________________________
From: David Brown <david@westcontrol.com>
Sent: Monday, January 22, 2018 10:14 AM
To: Jay K; gcc
Subject: Re: extern const initialized warns in C

Hi,

I made some points in my other reply.  But for completeness, I'll tackle
these too.

On 22/01/2018 10:38, Jay K wrote:
> Also the warning did not include a link explaining the desired workaround.
>
>
> Since you advocate for static...and I know it has big value..
>
> There are the following reasons against static:
>
>   - It is prohibited in some coding conventions.
>      They instead hide symbols by omitting them from any headers.

As noted before, that is insane.  It gives no benefits but makes it easy
to cause mistakes that are hard to find.

>
>   - It allows/encourages symbols duplicated from a human point of view,
>     leading to harder to read code; but this is also the point and good,
>     it offers scope to pick shorter names, or at least hide
>     names (you can still strive for globally unique names, in
>     case the symbols later have to be made extern)

Omitting "static" also allows symbol duplication.  It just means that
such duplication is an error in the code - which may or may not be
caught at link time.

You /can/ have a coding convention that discourages duplicate symbol
names - even when using "static".  That might help a little in
understanding, but will quickly mean bloated source code that is harder
to read and follow (because you end up with long-winded symbol names
everywhere).

Such conventions are not scalable, are hopeless for multi-programmer
projects, terrible for code re-use, and can make code far harder to read
and write.

The scoping and naming in C is limited enough without omitting half the
features it has to deal with modularisation.

>
>   - it leads to accidental duplication, static int foo = 123 in a header

It is quite simple - don't do that.  It is appropriate for constant data
- "static const int foo = 123;" in a header will be fine, because "foo"
has the same value everywhere and is likely to be "optimised away".
That is the reason C++ makes "const int foo = 123;" effectively static.

Headers (in C, and mostly in C++) are for /declarations/, not
definitions - at least if you want to write structured and modular code.

>
>   - There are toolsets that don't resolve statics in disassembly

Statics are local to the file.  Disassemblies should show them when they
are used.  For the tiny, tiny proportion of C programmers that ever use
a disassembler, if their toolchains are not good enough then they should
get better toolchains.  It should /never/ be a problem when using
assembly listing files generated by the compiler, which are almost
always more useful than disassembling object code.

Making a coding convention to suit this requirement is like making
gloves with 6 fingers so that they fit people with an extra digit.

>
>   - It only allows for sharing within a file and hiding from all others,
>     it doesn't allow sharing for within a few files and hiding from others

C has no good way to allow sharing between a few files and hiding from
others.  Such shared identifiers must be program-wide global.  But that
does /not/ mean you should make /everything/ program-wide global!  It
means you should minimise such sharing, prefix such shared names in a
way likely to minimise conflicts, and organise your source code modules
as best you can.

>
>   - It sort of doesn't work with "unity builds" old fashioned LTO/LTCG where one
>     source file includes the rest

It works /exactly/ as well.  Such "unity builds" need symbols to have
different identifiers - but you can quite happily declare them "static".

You seem to be under the impression that using "static" forces you to
use duplicate names for different objects in different files.  That is
not true - it merely /allows/ it.  You can still have a convention
requiring different identifiers in different modules.  It is a bad idea,
IMHO, but omitting "static" makes it far worse.

>
>     I think a linker switch to report symbols that could be static
>     might be useful.
>
>     I find the "scoping" too hard to pass it, and if I need to make
>     the symbol extern in future, I can afford a rename to do it.

I am not sure what you mean by that.

mvh.,

David


>
>
>      - Jay
>
>
>
>
> From: Jay K
> Sent: Monday, January 22, 2018 9:31 AM
> To: David Brown; gcc
> Subject: Re: extern const initialized warns in C
>
>
>
> By this argument there is a missing warning for the equivalent:
>
>    const int foo = 123;
>
> with no previous extern declaration.
>
> As well, there is no warning in C++.
> All three constructs are equivalent, yet only one gets a warning.
>
> Interesting point, that I had not realized, and with an often acceptable
> workaround, however also there exist coding conventions that prohibit use of static.
> Instead they "hide" things by omitting them from headers only.
>
> That can still be worked around, just put the declaration right before the definition,
> in the same source file.
>
> I realize there are many arguments for and against file level static.
>
>   - Jay
>
>
> From: David Brown <david@westcontrol.com>
> Sent: Monday, January 22, 2018 8:32 AM
> To: Jay K; gcc
> Subject: Re: extern const initialized warns in C
>
>
> On 21/01/18 08:12, Jay K wrote:
>> extern const int foo = 123;
>>
>>
>>
>> Why does this warn?
>> This is a valid portable form, with the same meaning
>> across all compilers, and, importantly, portably
>> to C and C++.
>>
>> I explicitly do not want to say:
>>
>>     const int foo = 123
>>
>> because I want the code to be valid and have the same meaning
>> in C and C++ (modulo name mangling).
>>
>> I end up with:
>>
>> // Workaround gcc warning.
>> #ifdef __cplusplus
>> #define EXTERN_CONST extern const
>> #else
>> #define EXTERN_CONST const
>> #endif
>>
>>
>> EXTERN_CONST int foo = 123;
>>
>> and having to explain it to people.
>>
>
> <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=45977>
45977 – "warning: 'i' initialized and declared 'extern ...<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=45977>
gcc.gnu.org
GCC Bugzilla – Bug 45977 "warning: 'i' initialized and declared 'extern'" could use a separate warning flag controlling it Last modified: 2017-07-26 15:36:22 UTC


>
>
> 45977 – "warning: 'i' initialized and declared 'extern ...
> gcc.gnu.org
> GCC Bugzilla – Bug 45977 "warning: 'i' initialized and declared 'extern'" could use a separate warning flag controlling it Last modified: 2017-07-26 15:36:22 UTC
>
>
> 45977 – "warning: 'i' initialized and declared 'extern ...
> gcc.gnu.org
> GCC Bugzilla – Bug 45977 "warning: 'i' initialized and declared 'extern'" could use a separate warning flag controlling it Last modified: 2017-07-26 15:36:22 UTC
>
> This suggests that gcc authors consider mixing "extern" and
> initialization to be such bad style that the compiler warns by default.
>   But the "bug" is that there is no flag to turn off this warning.
> (Ideally every warning should have a matching flag, even if the warning
> is enabled by default.)
>
> Usually you do not want to have "extern" and initialisation in the same
> line - it indicates a questionable organisation of your sources which is
> more likely to be error-prone than the standard idioms.  (I say
> "questionable", not necessarily wrong - but certainly I would question
> it if I saw it in source code.)
>
> Normally you want:
>
> // file.h
> // declaration, not definition
> extern const int foo;
>
> // file.c
> #include <file.h>
> // definition
> const int foo = 123;
>
> // otherfile.c
> #include <file.h>
> int usefoo(void) { return foo; }
>
>
> The key advantages of this sort of setup are a cleaner separation
> between declarations (which you need to /use/ things) and the
> definitions (which should normally only exist once in the program -
> certainly for C).  The declarations and definitions only exist in one
> place, and they are checked for consistency - there are no "extern"
> declarations lying around in C files that might get out of step from
> changes in the headers or other files with definitions.
>
> To be consistent with this, and to work consistently with C and C++, I
> have a strict policy that a C (or C++) file never contains  declarations
> without definitions (and initialisations as needed), with each
> definition either also declared as "extern" in a matching header file,
> or it is declared as "static".
>
> This sort of arrangement is very common - though many people are lazy
> about using "static".  (In C++, you can also use anonymous namespaces,
> but "static" works for consistency between C and C++.)
>
>
> Still, gcc should have a flag to disable this warning if you have reason
> to use "extern const int foo = 123;" - it is, after all, correctly
> defined C code.
>
>
>
>> $ cat 1.c
>> extern const int foo = 123;
>> $ $HOME/gcc720/bin/gcc -c -S 1.c
>> 1.c:1:18: warning: 'foo' initialized and declared 'extern'
>>    extern const int foo = 123;
>>                     ^~~
>> $ $HOME/gcc720/bin/gcc -c -S -xc++ -Wall -pedantic 1$ $HOME/gcc720/bin/gcc -v
>> Using built-in specs.
>>
>> COLLECT_GCC=/Users/jay/gcc720/bin/gcc
>> COLLECT_LTO_WRAPPER=/Users/jay/gcc720/libexec/gcc/x86_64-apple-darwin16.7.0/7.2.0/lto-wrapper
>> Target: x86_64-apple-darwin16.7.0
>> Configured with: ../gcc-7.2.0/configure -prefix=/Users/jay/gcc720 -disable-nls -disable-bootstrap
>> Thread model: posix
>> gcc version 7.2.0 (GCC) $
>>
>>
>> Thank you,
>>    - Jay
>>
>>
>>
>>
>>
>
>
>



More information about the Gcc mailing list