There is also always a two level namespace -- imported functions are
qualified
by the dll name they are expected to be in. For multiple dlls to export
the same function name creates no ambiguity and implies no replacement
of one by the other, and no semantic difference depending on load order.
Unless someone writes very wierd code calling dlopen/dlsym like crazy.
There is no LD_PRELOAD, slight loss, and replacing e.g. operator new
isn't really possible process-wide, only within the scope of the
static link,
and even that is so rare, that it is probably sufficient.
There is no going out of the way to accurately simulate the static linker
at dynamic link time. Functions are only exported if they are annotated
in source or listed in a separate file. Not just by being non-static.
- Jay
------------------------------------------------------------------------
*From:* David Brown <da...@westcontrol.com>
*Sent:* Monday, January 22, 2018 10:42 AM
*To:* Jay K; gcc
*Subject:* Re: extern const initialized warns in C
On 22/01/2018 11:14, Jay K wrote:
I meant:
extern const foo = 123;
does not warn in C++, but by these arguments, should.
Yes, I think it should. But I am a compiler user, not a compiler
author, so my bias is strongly towards /my/ code rather than a wider
audience.
I understand that const int foo = 123 is static in C++.
It is this difference between C and C++ and the desire to write code
that means the same in C and C++ is why I write extern const int foo =
123 in the first place. If I was just writing C forever and not planning
to compile as C++ ever then I would omit the redundant extern -- and not
get a warning -- the other inconsistency!
As I suggested, put the declaration in the header and the definition in
the source file. Then it is the same code for C and C++, works
correctly, and gives no warnings no matter what flags you use. And it
is modular, structured, and lets programmers see exactly what is
"exported" from that C file by looking in a short header rather than
digging through a long source file.
To repeat for clarity:
1 C: extern const int foo = 123; => warns, for reasons explained and
understood even if not agreed
2 C: const int foo = 123; => means the same thing, but no warning;
inconsistent?
3 C++: extern const int foo = 123; => also no warning, inconsistent?
The prohibition against file level static is actually quite widespread
and adhered to.
Can you give references or links? As I say, I think such a convention
is /seriously/ wrong.
(There are plenty of other conventions that I think are wrong - even
famous and "professional" standards like MISRA have some daft ideas.)
Along with it, of course, comes a mandate to pick globally unique names.
That mandate I can understand. There are rational justifications for
it, even though I don't agree with them and think it is unworkable
except for very small and limited programs. But there is nothing to
stop you using "static" along with the globally unique names.
Given a large C code base with many external identifiers, the extra step
of barring static and requiring incrementally more symbols to be unique
is not clearly a big deal. I already have to ensure uniqueness of many
symbols, what is a few more?
The majority of your file-level identifiers in a C file will normally
/not/ be exported - they will only ever be used internally. I have no
statistics, but I'd guess that under 10% of most C file's file-level
identifiers are used externally in my "average" C file. That means only
10% need to be globally unique.
But I understand, perhaps in other systems, statics vastly outnumber
externs, and the condition would be a large increment not a small one.
Yes, exactly. Of course this sort of thing will vary somewhat depending
on the type of coding you are doing.
While I struggle not bite my tongue advocating switching from C to C++,
this factor seems much less sigificant or harmful.
I don't follow. If you want to switch from C to C++, that's fine by me
:-) C++ gives you namespaces, which gives you another way to group your
identifiers and control their scope.
I have actually seen and heard of the accidental duplication of symbols
due to static multiple times.
If you put your static variables in the C file, it is not "accidental"
duplication - they are different objects. If you put static (non-const)
variables in your header files, you have misunderstood how to use header
files in C programming.
I also do a "unity build" (one source file includes the rest) of my own
code to eek out a little extra performance (even while already using
LTO/LTCG) and had to work out the static duplication.
Using "static" does not hinder that. And it can be a significant
benefit in performance. So far, we have been looking at this from the
viewpoint of code correctness, easy of reading and writing the code, and
avoiding subtle errors. But since you are interested in performance or
code size, then you /really/ should be using "static" at every possible
opportunity. It makes a large difference - both for code size and
speed, when you have "static" on your variables and functions that don't
have to be globally visible.
You mention the debugger ease of use.
I haven't seen debuggers struggle with static but I have seen file
dumpers struggle (not objdump per se, but similar)
I use the debugger as a better disassembler instead for this very
reason, debugger can just load up a file for examination without running
anything.
And then, you should realize there are very large systems that output
nightly builds with symbols, taking hours on fast machines, where
individual developers only build their little part of the tree, but
debug anything.
I realise that. And "static" is your friend there too. I could not
imagine trying to use a large build system or multiple developers where
everything is global and shared, and you are trying to keep unique names
everywhere. It is a recipe for pointlessly increasing build times, and
massively increasing developer time.
In these systems, it behooves the mainline source to be debuggable, and
not rely on temporary edits and rebuilds.
That is, if you would remove static for temporary debuggability, then it
follows you should remove it for long term debuggability.
No, you would only remove "static" for temporary debugging of a local
section of code - not for a big debugging session of such massive
builds. It is just one of the many types of small temporary code
changes that can be helpful during debugging, such as adding "volatile"
or extra "printf".
There is an amazing diversity of coding styles/idioms and C and C++
compilers need to be ridiculously careful in imposing or suggesting
restrictions. I strive to be warning-free as well, perhaps untenable.
Yes, there are lots of conventions and styles. And as I have said, I
fully agree that there should be a flag for this particular issue.
People have the right to make poor choices if they want (especially
since these poor choices are usually made by a PHB or some ancient
programmer who hasn't noticed that the world has changed during the last
20+ years and still thinks K&R is the defining word on C - and the
unfortunate low-rank programmers just have to live with them).
(Apologies if I sound too harsh in my opinions here - they come from
being an ancient programmer who /has/ noticed how things have changed
over the last 20+ years. But I work in a relatively narrow field -
small systems embedded programming - and your experience may differ in
other fields.)
mvh.,
David
- Jay
------------------------------------------------------------------------
*From:* David Brown <da...@westcontrol.com>
*Sent:* Monday, January 22, 2018 9:53 AM
*To:* Jay K; gcc
*Subject:* Re: extern const initialized warns in C
On 22/01/2018 10:31, Jay K wrote:
By this argument there is a missing warning for the equivalent:
const int foo = 123;
with no previous extern declaration.
I would like to see such a warning. There is "-Wmissing-declarations",
but that applies only to functions and not to objects.
(Note that in C++, "const" objects without an "extern" declaration are
effectively "static" - in C, without the storage-class specifier const
objects have external linkage.)
As well, there is no warning in C++.
All three constructs are equivalent, yet only one gets a warning.
No, they are not the same - in C++ the linkage of a const is static
unless you explicitly say "extern", and in C it is external unless you
explicitly say "static".
Thus in "extern const int foo = 123;", the "extern" has a significant
effect in C++ but in C it does nothing (other than inform the reader).
I would like to see the warning having a controlling flag. It could
perhaps be on by default in C and off by default in C++ to get the same
effect as today - and then users can fine-tune to fit their style.
Interesting point, that I had not realized, and with an often acceptable
workaround, however also there exist coding conventions that prohibit use of
static.
I have never heard of such a thing in a coding standard. C++
conventions might encourage the use of anonymous namespaces rather than
C-style "static" declarations, but that would not apply to C. I would
consider a coding convention that discouraged static to be seriously broken.
Instead they "hide" things by omitting them from headers only.
That is madness. The symbols still have global linkage across the
program, and you will get all sorts of problems when one file uses the
same "local" identifier as another. If you are lucky, your linker will
tell you of the crash - but if you have enabled "common" data (i.e., you
don't have the "-fno-common" flag) and have used the same identifier for
two different "local" objects without explicit initialisation, you are
going to have some serious and very hard to find bugs.
If someone asks you to write to such a coding convention, do your best
to refuse.
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.
There are no /good/ arguments against file-level static in C, except
perhaps temporarily while debugging (it can be easier to view non-static
data in a debugger). Any time file-level static can be used, it
/should/ be used.
IMHO, of course.
mvh.,
David
- 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 ...
<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 ...
<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
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