Deutsch   English   Français   Italiano  
<vtammh$174ev$1@dont-email.me>

View for Bookmarking (what is this?)
Look up another Usenet article

Path: ...!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!eternal-september.org!.POSTED!not-for-mail
From: David Brown <david.brown@hesbynett.no>
Newsgroups: comp.lang.c
Subject: Re: do { quit; } else { }
Date: Fri, 11 Apr 2025 11:17:04 +0200
Organization: A noiseless patient Spider
Lines: 136
Message-ID: <vtammh$174ev$1@dont-email.me>
References: <vspbjh$8dvd$1@dont-email.me> <8634enhcui.fsf@linuxsc.com>
 <vsph6b$ce6m$5@dont-email.me> <86ldsdfocs.fsf@linuxsc.com>
 <20250406161323.00005809@yahoo.com> <86ecy5fjin.fsf@linuxsc.com>
 <20250406190321.000001dc@yahoo.com> <86plhodtsw.fsf@linuxsc.com>
 <20250407210248.00006457@yahoo.com> <vt15lq$bjs0$3@dont-email.me>
 <vt2lp6$1qtjd$1@dont-email.me> <vt31m5$2513i$1@dont-email.me>
 <vt3d4g$2djqe$1@dont-email.me> <vt3iqh$2ka99$1@dont-email.me>
 <vt5fed$ccri$1@dont-email.me> <vt5js2$g1t7$1@dont-email.me>
 <20250409142303.00004645@yahoo.com> <87ikndqabc.fsf@nosuchdomain.example.com>
 <20250410115501.000037a5@yahoo.com> <vt8ei8$2vn84$1@dont-email.me>
 <20250410080629.532@kylheku.com> <vt94q5$3jjod$1@dont-email.me>
 <vt9628$3hhr8$3@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
Injection-Date: Fri, 11 Apr 2025 11:17:06 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="414a89bbcf5f663aa3944451ac130353";
	logging-data="1282527"; mail-complaints-to="abuse@eternal-september.org";	posting-account="U2FsdGVkX18s/2hrKJFHoPf9KOFL2ALnwREn8syQoaY="
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
 Thunderbird/102.11.0
Cancel-Lock: sha1:0omsfWKLAqVb8Mdf/q0xKkkQQA8=
In-Reply-To: <vt9628$3hhr8$3@dont-email.me>
Content-Language: en-GB
Bytes: 7638

On 10/04/2025 21:27, bart wrote:
> On 10/04/2025 20:05, David Brown wrote:
>> On 10/04/2025 17:41, Kaz Kylheku wrote:
>>> 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).
> 
> It can't be that simple in C because of shared headers.
> 
> 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
> 

Yes.

In A.c, "abc" is declared to have external linkage, then it is declared 
with external linkage and defined.

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

"Linkage" is about the /link/, not one side of the link (export or 
import).  "extern" declares external linkage.

Some other programming languages make the distinction between import and 
export.  That can work too, if you have enough extra support (such as 
compiled "interface" files generated from an exporting module).  Without 
that support - such as is the case for most assembly languages - it's 
very easy to get mixups between what one assembly file "foo.asm" exports 
and what other modules import from "foo.inc".  One way to handle that 
limitation is a whole collection of messy macros.  I've been there, done 
that, and am glad to have left it behind.


> 
>>
>> C rarely makes things more complicated without a good reason.
> 
> C usually makes things more complicated without a good reason!

Nope.

> 
> Here's one example, of dozens, of perfectly legal C:
> 
>    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;
>    .....
> 

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.

(Putting storage-class specifiers other than at the start of a 
declaration has been obsolescent since at least C99 - but it has not 
been removed from the language.  I think that is because it would be 
extra work in specifying the syntax rules, rather than because many 
people write declarations like yours.)

Nothing will ever stop some programmers from writing complicated or 
messy code.