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