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 <da...@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 ...
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




Reply via email to