Liste des Groupes | Revenir à cl c |
On 10/04/2025 20:05, David Brown wrote:Yes.On 10/04/2025 17:41, Kaz Kylheku wrote:It can't be that simple in C because of shared headers.On 2025-04-10, David Brown <david.brown@hesbynett.no> wrote:>So currently, I have no explanation for why you may write "static int>
foo; extern int foo;" and have "foo" be internal linkage, while "extern
int foo; static int foo;" is not allowed.
What's also not allowed is "static int foo; int foo;" !
>
It's because "extern" means "refer to the existing file scope
declaration of the identifer if there is one propagating its
properties, including linkage; otherwise if it doesn't exist,
create an external linkage reference"
>
That's a summary of how "extern" works, but it results in a kind of circular argument or tautology - it's just saying "extern means what it means". It does not explain /why/ it works this way, or where the rules came from, why C has use of a single keyword that works this way, and why it is called "extern".
>
It would be much simpler if we had "static int x;" to mean "declare x with internal linkage and define it", "extern int x;" to mean "declare x to have extern linkage", and "int x;" to mean "declare x with external linkage and define it". That is how you use these in most circumstances (and there are gcc warning flags to enforce it, for those that want to do that).
If module A wants to export 'abc' to other modules, then the source code seen by the compiler for A.c has to look like this:
extern int abc; // in A.h
......
int abc; // in A.c
The other modules include A.h and see 'extern int abc' which means 'abc' is imported.There is no "import" or "export" in C - only "internal linkage" or "external linkage" - file local or program global, if you prefer. The combinations "declare with external linkage but do not define" and "declare with external linkage and define" are used to achieve import and export of identifiers.
But its home module sees both of these, including the 'extern' version, but here 'abc' is exported!Yes - "extern" does /not/ mean "export".
That is counter-intuitive: how can a module both import a name (via 'extern int') and export it (via 'int' without 'static')?If the keyword "extern" were written "export", I'd agree on it being counter-intuitive. But it is not written that way. The point of "extern" is that it indicates external linkage - program-wide sharing of the identifier in question. It is shared amongst the units that exports it (by defining it) and units that import it (by using it), usually achieved by having the same shared header included by the exporting unit and the importing units. This has a huge advantage compared to languages where importing units read some kind of interface import file but the exporting one does not - it is extremely easy in C to ensure that all your shared identifiers match up correctly by keeping all external declarations in shared headers and all definitions in C files.
You can't say that A.h is only for consumption by other modules, since it could include stuff that all module including A will need, such as macros, types and enums.Of course - "A.h" is /not/ only for consumption by other translation units. (Please call them "translation units" or just "C files", not "modules" since we are discussing the C alternatives to code modules found in some other languages.) "A.h" is for consumption in "A.c" as well. This is the normal way of structuring C code.
So, here C is complicated because the same attribute has to mean different things depending on whether this is the entity's home module or not.No, it means /exactly/ the same thing in both situations.
Nope.>C usually makes things more complicated without a good reason!
C rarely makes things more complicated without a good reason.
Here's one example, of dozens, of perfectly legal C:That is not more complicated, nor is it without good reason. The language quite simply doesn't bother insisting on a specific order for some parts of declarations. It is simpler to describe in the standard.
long unsigned const long const const typedef int A;
int long unsigned const long const const typedef A;
long unsigned const long const typedef int A;
.....
Les messages affichés proviennent d'usenet.