Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #397206 > unrolled thread

gcc and 'include'

Started byBart <bc@freeuk.com>
First post2026-03-26 22:36 +0000
Last post2026-03-30 00:41 -0700
Articles 20 on this page of 66 — 10 participants

Back to article view | Back to comp.lang.c


Contents

  gcc and 'include' Bart <bc@freeuk.com> - 2026-03-26 22:36 +0000
    Re: gcc and 'include' Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-03-26 16:12 -0700
      Re: gcc and 'include' Bart <bc@freeuk.com> - 2026-03-27 10:55 +0000
        Re: gcc and 'include' David Brown <david.brown@hesbynett.no> - 2026-03-27 13:49 +0100
        Re: gcc and 'include' Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-03-27 10:51 -0700
          Re: gcc and 'include' Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-04-25 10:09 -0700
            Re: gcc and 'include' Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-04-25 15:58 -0700
        Re: gcc and 'include' Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-03-27 21:27 +0000
          Re: gcc and 'include' Bart <bc@freeuk.com> - 2026-03-27 22:05 +0000
            Re: gcc and 'include' Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-03-27 17:03 -0700
            Re: gcc and 'include' Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2026-03-28 05:10 +0100
            Re: gcc and 'include' Michael S <already5chosen@yahoo.com> - 2026-03-28 20:37 +0300
              Re: gcc and 'include' Bart <bc@freeuk.com> - 2026-03-28 18:33 +0000
                Re: gcc and 'include' antispam@fricas.org (Waldek Hebisch) - 2026-03-29 00:53 +0000
                  Re: gcc and 'include' Bart <bc@freeuk.com> - 2026-03-29 22:37 +0100
                    Re: gcc and 'include' Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-03-30 05:33 -0700
                      Re: gcc and 'include' Bart <bc@freeuk.com> - 2026-03-30 14:42 +0100
                        Re: gcc and 'include' Michael S <already5chosen@yahoo.com> - 2026-03-30 16:53 +0300
                          Re: gcc and 'include' Bart <bc@freeuk.com> - 2026-03-30 18:11 +0100
                        Re: gcc and 'include' Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-03-30 08:27 -0700
                        Re: gcc and 'include' Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-03-30 11:54 -0700
                          Re: gcc and 'include' Bart <bc@freeuk.com> - 2026-03-30 21:54 +0100
                            Re: gcc and 'include' Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-03-30 18:07 -0700
                              Re: gcc and 'include' Bart <bc@freeuk.com> - 2026-03-31 11:39 +0100
                                Re: gcc and 'include' Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-03-31 13:56 -0700
                                  Re: gcc and 'include' Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-04-06 20:56 -0700
                                    Re: gcc and 'include' Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-04-06 23:12 -0700
                        Re: gcc and 'include' James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-03-30 21:06 -0400
                Re: gcc and 'include' David Brown <david.brown@hesbynett.no> - 2026-03-29 11:24 +0200
                  Re: gcc and 'include' Bart <bc@freeuk.com> - 2026-03-29 12:44 +0100
                    Re: gcc and 'include' David Brown <david.brown@hesbynett.no> - 2026-03-31 15:57 +0200
              Re: gcc and 'include' Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-03-30 07:20 -0700
            Re: gcc and 'include' Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-03-30 05:07 -0700
    Re: gcc and 'include' Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-03-27 00:25 +0000
      Re: gcc and 'include' Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-03-30 07:13 +0000
        Re: gcc and 'include' Andrey Tarasevich <noone@noone.net> - 2026-03-30 07:54 -0700
          Re: gcc and 'include' Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-03-31 01:46 +0000
            Re: gcc and 'include' antispam@fricas.org (Waldek Hebisch) - 2026-03-31 05:28 +0000
    Re: gcc and 'include' Michael S <already5chosen@yahoo.com> - 2026-03-27 04:10 +0300
      Re: gcc and 'include' Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-03-26 19:08 -0700
        Re: gcc and 'include' Michael S <already5chosen@yahoo.com> - 2026-03-27 16:47 +0300
          Re: gcc and 'include' David Brown <david.brown@hesbynett.no> - 2026-03-27 16:43 +0100
          Re: gcc and 'include' Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-03-27 09:03 -0700
            Re: gcc and 'include' Michael S <already5chosen@yahoo.com> - 2026-03-29 11:46 +0300
              Re: gcc and 'include' Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-03-30 08:19 -0700
                Re: gcc and 'include' Michael S <already5chosen@yahoo.com> - 2026-03-30 20:08 +0300
                  Re: gcc and 'include' Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-03-31 00:26 -0700
                    Re: gcc and 'include' Michael S <already5chosen@yahoo.com> - 2026-03-31 11:27 +0300
                      Re: gcc and 'include' Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-04-07 09:45 -0700
          Re: gcc and 'include' Andrey Tarasevich <noone@noone.net> - 2026-03-28 10:25 -0700
            Re: gcc and 'include' Michael S <already5chosen@yahoo.com> - 2026-03-29 10:37 +0300
              Re: gcc and 'include' David Brown <david.brown@hesbynett.no> - 2026-03-29 11:30 +0200
              Re: gcc and 'include' Andrey Tarasevich <noone@noone.net> - 2026-03-29 07:22 -0700
              Re: gcc and 'include' James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-03-29 13:56 -0400
                Re: gcc and 'include' Michael S <already5chosen@yahoo.com> - 2026-03-29 21:39 +0300
                  Re: gcc and 'include' James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-03-29 20:08 -0400
                    Re: gcc and 'include' Bart <bc@freeuk.com> - 2026-03-30 01:58 +0100
                  Re: gcc and 'include' Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-03-30 07:59 -0700
    Re: gcc and 'include' Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-03-26 19:06 -0700
    Re: gcc and 'include' Bart <bc@freeuk.com> - 2026-03-27 16:20 +0000
      Re: gcc and 'include' David Brown <david.brown@hesbynett.no> - 2026-03-27 18:07 +0100
      Re: gcc and 'include' James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-03-28 18:48 -0400
    Re: gcc and 'include' Andrey Tarasevich <noone@noone.net> - 2026-03-27 22:38 -0700
      Re: gcc and 'include' Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-03-28 00:30 -0700
        Re: gcc and 'include' Andrey Tarasevich <noone@noone.net> - 2026-03-29 16:15 -0700
          Re: gcc and 'include' Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-03-30 00:41 -0700

Page 1 of 4  [1] 2 3 4  Next page →


#397206 — gcc and 'include'

FromBart <bc@freeuk.com>
Date2026-03-26 22:36 +0000
Subjectgcc and 'include'
Message-ID<10q4ceb$38i2d$1@dont-email.me>
Take this program:

   #include <stdlib.h>

   inline int F(){return rand();}

   int main(void) {
       return F();
   }

This compiles fine with gcc using -O1 -O2 -O3.

But compile without optimising, and it fails to link as it can't find a 
function 'F'.

Is it supposed to behave like that? I assume no discrete function F is 
being generated because of the 'inline' attribute, but you'd think it 
would ignore that if inlining wasn't enabled.

It compiles fine with or without 'inline' using tcc and bcc (my product).

Clang fails too, but clearly only because it has to duplicate gcc's 
behaviour for drop-in compatability, even if it is crass.

(This is the actual program: 
https://web.archive.org/web/20010127204000/http://www.bagley.org/~doug/shootout/bench/lists/lists.gcc)

[toc] | [next] | [standalone]


#397207

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-03-26 16:12 -0700
Message-ID<87ikaiw5g0.fsf@example.invalid>
In reply to#397206
Bart <bc@freeuk.com> writes:
> Take this program:
>
>   #include <stdlib.h>
>
>   inline int F(){return rand();}
>
>   int main(void) {
>       return F();
>   }
>
> This compiles fine with gcc using -O1 -O2 -O3.
>
> But compile without optimising, and it fails to link as it can't find
> a function 'F'.
>
> Is it supposed to behave like that? I assume no discrete function F is
> being generated because of the 'inline' attribute, but you'd think it
> would ignore that if inlining wasn't enabled.
>
> It compiles fine with or without 'inline' using tcc and bcc (my product).
>
> Clang fails too, but clearly only because it has to duplicate gcc's
> behaviour for drop-in compatability, even if it is crass.
>
> (This is the actual program:
> https://web.archive.org/web/20010127204000/http://www.bagley.org/~doug/shootout/bench/lists/lists.gcc)

I don't have an answer to your question, but defining F as
"static inline" makes the program work.  You can also do this:

    inline int F();
    int F(){return rand();}

(Unless you're using a C23 compiler, I suggest "int F(void)" rather
than "int F()".)

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#397221

FromBart <bc@freeuk.com>
Date2026-03-27 10:55 +0000
Message-ID<10q5nnr$3l3lc$1@dont-email.me>
In reply to#397207
On 26/03/2026 23:12, Keith Thompson wrote:
> Bart <bc@freeuk.com> writes:
>> Take this program:
>>
>>    #include <stdlib.h>
>>
>>    inline int F(){return rand();}
>>
>>    int main(void) {
>>        return F();
>>    }
>>
>> This compiles fine with gcc using -O1 -O2 -O3.
>>
>> But compile without optimising, and it fails to link as it can't find
>> a function 'F'.
>>
>> Is it supposed to behave like that? I assume no discrete function F is
>> being generated because of the 'inline' attribute, but you'd think it
>> would ignore that if inlining wasn't enabled.
>>
>> It compiles fine with or without 'inline' using tcc and bcc (my product).
>>
>> Clang fails too, but clearly only because it has to duplicate gcc's
>> behaviour for drop-in compatability, even if it is crass.
>>
>> (This is the actual program:
>> https://web.archive.org/web/20010127204000/http://www.bagley.org/~doug/shootout/bench/lists/lists.gcc)
> 
> I don't have an answer to your question, but defining F as
> "static inline" makes the program work.  You can also do this:
> 
>      inline int F();
>      int F(){return rand();}


Using 'static' to force an actual function to be generated sounds 
unintuitive. It is when F is exported to be called from another module 
that a tangible F function needs to exist.

But my example came from some pre-existing legacy code, where I was 
surprised that -O0 made it fail.

> (Unless you're using a C23 compiler, I suggest "int F(void)" rather
> than "int F()".)


Nobody bothers with that any more. Most seem to assume that () already 
means zero parameters anyway, judging by the incorrect usage I 
constantly saw in open source code.

[toc] | [prev] | [next] | [standalone]


#397222

FromDavid Brown <david.brown@hesbynett.no>
Date2026-03-27 13:49 +0100
Message-ID<10q5ud7$3np50$1@dont-email.me>
In reply to#397221
On 27/03/2026 11:55, Bart wrote:
> On 26/03/2026 23:12, Keith Thompson wrote:
>> Bart <bc@freeuk.com> writes:
>>> Take this program:
>>>
>>>    #include <stdlib.h>
>>>
>>>    inline int F(){return rand();}
>>>
>>>    int main(void) {
>>>        return F();
>>>    }
>>>
>>> This compiles fine with gcc using -O1 -O2 -O3.
>>>
>>> But compile without optimising, and it fails to link as it can't find
>>> a function 'F'.
>>>
>>> Is it supposed to behave like that? I assume no discrete function F is
>>> being generated because of the 'inline' attribute, but you'd think it
>>> would ignore that if inlining wasn't enabled.
>>>
>>> It compiles fine with or without 'inline' using tcc and bcc (my 
>>> product).
>>>
>>> Clang fails too, but clearly only because it has to duplicate gcc's
>>> behaviour for drop-in compatability, even if it is crass.
>>>
>>> (This is the actual program:
>>> https://web.archive.org/web/20010127204000/http://www.bagley.org/~doug/shootout/bench/lists/lists.gcc)
>>
>> I don't have an answer to your question, but defining F as
>> "static inline" makes the program work.  You can also do this:
>>
>>      inline int F();
>>      int F(){return rand();}
> 
> 
> Using 'static' to force an actual function to be generated sounds 
> unintuitive. It is when F is exported to be called from another module 
> that a tangible F function needs to exist.
> 
> But my example came from some pre-existing legacy code, where I was 
> surprised that -O0 made it fail.
> 

I agree with you that this behaviour can be surprising, but it is 
correct according to the C standards.  "inline" alone in C means that 
the compiler /may/ use the inline definition in code generation - but it 
may also use a normal external linkage definition found at link time. 
The inline definition and the external definition do not have to be the 
same - it is fine to have a local inline version in a file that is 
different from the external one.

For example, you could have a normal function in your program called 
"sort" that can sort arrays of any size.  But you know that in this one 
particular C file, you only ever need to sort arrays of size 4.  You 
write a specialised version - keeping the same name "sort" and the same 
function signature, and mark it "inline".  The compiler can choose 
either version when generating the code - the local inline version, or 
the external version.  Typically you get the local version when 
optimising.  (The compiler can always choose the local version even when 
you have used a flag like "-O0" - the C standard does not care about 
optimisation.)

But this all also means that even when you have a version of the 
function locally with "inline", the compiler can choose to generate code 
that refers to an externally linked version.  This is the normal 
behaviour for compilers when you are not optimising (though again the 
standard does not require this).  A common reason for not optimising 
code is because you want to debug it, and that can be easier with a 
single external version of the function - perhaps you want to put a 
breakpoint in it when using a debugger, or add printf statements, or 
whatever.


Another source of confusion here is that this is all subtly different 
from C++'s "inline", as well as the "gnu89" "inline" that gcc supported 
as an extension before C99 was published.  In both these cases, the 
local "inline" function will be used (whether it is actually generated 
inline or as a function call is up to the compiler optimisation).  But 
you are free to have an external version of the function as well, 
without conflict.


Generally, as Keith suggested, it is best to use "static inline" rather 
than plain "inline".  Then the code is logically a static function - 
callers will always use the local copy, and nothing is exported.  You 
can also use "extern inline" which marks the function as being available 
for local inlining, and the definition is also available for external 
linkage.  But "static inline" is by far the most common.  Both "static 
inline" and "extern inline" work the same way for C99 inline, gnu89 
inline and C++ inline.


>> (Unless you're using a C23 compiler, I suggest "int F(void)" rather
>> than "int F()".)
> 
> 
> Nobody bothers with that any more. Most seem to assume that () already 
> means zero parameters anyway, judging by the incorrect usage I 
> constantly saw in open source code.
> 

I think almost all C programmers write "int foo(void);", not "int 
foo();".  The exception is primarily people who are used to writing C++ 
rather than C.  You can omit the "void" in the definition of a function 
with no parameters, but I don't see any good reason to do that.



[toc] | [prev] | [next] | [standalone]


#397233

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-03-27 10:51 -0700
Message-ID<87pl4pnotc.fsf@example.invalid>
In reply to#397221
Bart <bc@freeuk.com> writes:
> On 26/03/2026 23:12, Keith Thompson wrote:
[...]
>> (Unless you're using a C23 compiler, I suggest "int F(void)" rather
>> than "int F()".)
>
> Nobody bothers with that any more.

I presume that's meant to be hyperbole.  Plenty of C programmers do
bother with that.

>                                    Most seem to assume that () already
> means zero parameters anyway, judging by the incorrect usage I
> constantly saw in open source code.

I find it better to write correct code than to look for excuses
to write poor code.  If I define a parameterless function F, I
absolutely want a diagnostic if I call it with one or more arguments.
If nothing else, it's an opportunity to set a good example.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#397941

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-04-25 10:09 -0700
Message-ID<86wlxv2chg.fsf@linuxsc.com>
In reply to#397233
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

> Bart <bc@freeuk.com> writes:
>
>> On 26/03/2026 23:12, Keith Thompson wrote:
>
> [...]
>
>>> (Unless you're using a C23 compiler, I suggest "int F(void)" rather
>>> than "int F()".)
>>
>> Nobody bothers with that any more.
>
> I presume that's meant to be hyperbole.  Plenty of C programmers do
> bother with that.
>
>>                                    Most seem to assume that () already
>> means zero parameters anyway, judging by the incorrect usage I
>> constantly saw in open source code.
>
> I find it better to write correct code than to look for excuses
> to write poor code.  If I define a parameterless function F, I
> absolutely want a diagnostic if I call it with one or more arguments.
> If nothing else, it's an opportunity to set a good example.

The declaration "int F();" is correct code.  Just because you
don't like it doesn't mean it's wrong.

[toc] | [prev] | [next] | [standalone]


#397956

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-04-25 15:58 -0700
Message-ID<10sjguu$1668o$7@kst.eternal-september.org>
In reply to#397941
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>> Bart <bc@freeuk.com> writes:
>>> On 26/03/2026 23:12, Keith Thompson wrote:
>> [...]
>>
>>>> (Unless you're using a C23 compiler, I suggest "int F(void)" rather
>>>> than "int F()".)
>>>
>>> Nobody bothers with that any more.
>>
>> I presume that's meant to be hyperbole.  Plenty of C programmers do
>> bother with that.
>>
>>>                                    Most seem to assume that () already
>>> means zero parameters anyway, judging by the incorrect usage I
>>> constantly saw in open source code.
>>
>> I find it better to write correct code than to look for excuses
>> to write poor code.  If I define a parameterless function F, I
>> absolutely want a diagnostic if I call it with one or more arguments.
>> If nothing else, it's an opportunity to set a good example.
>
> The declaration "int F();" is correct code.  Just because you
> don't like it doesn't mean it's wrong.

You're right.  I see that I unintentionally implied that it's wrong.
I should have written "good code" rather than "correct code".

"int F()" is correct code.  For pre-C23 versions of C, it is in my
opinion inferior to "int F(void)".

I'm aware that you think "int F()" has some advantages in some
circumstances.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#397234

FromLawrence D’Oliveiro <ldo@nz.invalid>
Date2026-03-27 21:27 +0000
Message-ID<10q6snp$2nka$5@dont-email.me>
In reply to#397221
On Fri, 27 Mar 2026 10:55:55 +0000, Bart wrote:

> Using 'static' to force an actual function to be generated sounds
> unintuitive.

Lots of things about C are “unintuitive”. Coming from Pascal, I found
its type-definition syntax completely backwards.

[toc] | [prev] | [next] | [standalone]


#397235

FromBart <bc@freeuk.com>
Date2026-03-27 22:05 +0000
Message-ID<10q6uv4$419b$1@dont-email.me>
In reply to#397234
On 27/03/2026 21:27, Lawrence D’Oliveiro wrote:
> On Fri, 27 Mar 2026 10:55:55 +0000, Bart wrote:
> 
>> Using 'static' to force an actual function to be generated sounds
>> unintuitive.
> 
> Lots of things about C are “unintuitive”. Coming from Pascal, I found
> its type-definition syntax completely backwards.

If only it was simply backwards! Instead it's inside-out and spirular.

But, yeah, some C aspect being unintuitive is nothing new:

   extern int abc;
   int abc = 123;

Or:

   static int abc;
   extern int abc;

Both are valid C, but this isn't:

   extern int abc;
   static int abc;


I dare not ask what the rules are; I'm sure they exist, but they still 
don't make sense. I can only find out which of these are valid or not by 
trial and error. A HLL shouldn't be like that.

[toc] | [prev] | [next] | [standalone]


#397236

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-03-27 17:03 -0700
Message-ID<87fr5kx1jr.fsf@example.invalid>
In reply to#397235
Bart <bc@freeuk.com> writes:
[...]
> I dare not ask what the rules are; I'm sure they exist, but they still
> don't make sense. I can only find out which of these are valid or not
> by trial and error. A HLL shouldn't be like that.
[...]

Fortunately, there's a standard.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#397239

FromJanis Papanagnou <janis_papanagnou+ng@hotmail.com>
Date2026-03-28 05:10 +0100
Message-ID<10q7kb0$aibc$1@dont-email.me>
In reply to#397235
On 2026-03-27 23:05, Bart wrote:
> On 27/03/2026 21:27, Lawrence D’Oliveiro wrote:
>> On Fri, 27 Mar 2026 10:55:55 +0000, Bart wrote:
>>
>>> Using 'static' to force an actual function to be generated sounds
>>> unintuitive.
>>
>> Lots of things about C are “unintuitive”. Coming from Pascal, I found
>> its type-definition syntax completely backwards.

Is there any [non-C-derived] language that had a similar convoluted
form?

> If only it was simply backwards! Instead it's inside-out and spirular.

LOL! - nice formulation. (You made my day.)

(The "C" declaration syntax somehow reminds me the US date format;
yeah, neither forwards nor backwards.)

Janis

[toc] | [prev] | [next] | [standalone]


#397255

FromMichael S <already5chosen@yahoo.com>
Date2026-03-28 20:37 +0300
Message-ID<20260328203718.00005c70@yahoo.com>
In reply to#397235
On Fri, 27 Mar 2026 22:05:24 +0000
Bart <bc@freeuk.com> wrote:

> On 27/03/2026 21:27, Lawrence D’Oliveiro wrote:
> > On Fri, 27 Mar 2026 10:55:55 +0000, Bart wrote:
> >   
> >> Using 'static' to force an actual function to be generated sounds
> >> unintuitive.  
> > 
> > Lots of things about C are “unintuitive”. Coming from Pascal, I
> > found its type-definition syntax completely backwards.  
> 
> If only it was simply backwards! Instead it's inside-out and spirular.
> 
> But, yeah, some C aspect being unintuitive is nothing new:
> 
>    extern int abc;
>    int abc = 123;
> 
> Or:
> 
>    static int abc;
>    extern int abc;
> 
> Both are valid C, but this isn't:
> 
>    extern int abc;
>    static int abc;
> 
> 
> I dare not ask what the rules are; I'm sure they exist, but they
> still don't make sense. I can only find out which of these are valid
> or not by trial and error. A HLL shouldn't be like that.

Why do you care?
As C programmer, all you have to know is to never use either 2nd or
3rd, because even if one of them can be legal according to Standard,
both of them certainly make no sense.

For your first example, it sometimes make sense, typically as result of
#inclyde and/or marcro substitution. What exactly do you find
unintuitive about it?








[toc] | [prev] | [next] | [standalone]


#397256

FromBart <bc@freeuk.com>
Date2026-03-28 18:33 +0000
Message-ID<10q96uf$rjbn$1@dont-email.me>
In reply to#397255
On 28/03/2026 17:37, Michael S wrote:
> On Fri, 27 Mar 2026 22:05:24 +0000
> Bart <bc@freeuk.com> wrote:
> 
>> On 27/03/2026 21:27, Lawrence D’Oliveiro wrote:
>>> On Fri, 27 Mar 2026 10:55:55 +0000, Bart wrote:
>>>    
>>>> Using 'static' to force an actual function to be generated sounds
>>>> unintuitive.
>>>
>>> Lots of things about C are “unintuitive”. Coming from Pascal, I
>>> found its type-definition syntax completely backwards.
>>
>> If only it was simply backwards! Instead it's inside-out and spirular.
>>
>> But, yeah, some C aspect being unintuitive is nothing new:
>>
>>     extern int abc;
>>     int abc = 123;
>>
>> Or:
>>
>>     static int abc;
>>     extern int abc;
>>
>> Both are valid C, but this isn't:
>>
>>     extern int abc;
>>     static int abc;
>>
>>
>> I dare not ask what the rules are; I'm sure they exist, but they
>> still don't make sense. I can only find out which of these are valid
>> or not by trial and error. A HLL shouldn't be like that.
> 
> Why do you care?
> As C programmer,

I'm also an implementer.

> all you have to know is to never use either 2nd or
> 3rd, because even if one of them can be legal according to Standard,
> both of them certainly make no sense.
> 
> For your first example, it sometimes make sense, typically as result of
> #inclyde and/or marcro substitution. What exactly do you find
> unintuitive about it?

That you declare 'abc' as something to be imported, yet in the next line 
it is initialised as though it was exported.

[toc] | [prev] | [next] | [standalone]


#397260

Fromantispam@fricas.org (Waldek Hebisch)
Date2026-03-29 00:53 +0000
Message-ID<10q9t6d$2p36t$1@paganini.bofh.team>
In reply to#397256
Bart <bc@freeuk.com> wrote:
> On 28/03/2026 17:37, Michael S wrote:
>> On Fri, 27 Mar 2026 22:05:24 +0000
>> Bart <bc@freeuk.com> wrote:
>> 
>>> On 27/03/2026 21:27, Lawrence D’Oliveiro wrote:
>>>> On Fri, 27 Mar 2026 10:55:55 +0000, Bart wrote:
>>>>    
>>>>> Using 'static' to force an actual function to be generated sounds
>>>>> unintuitive.
>>>>
>>>> Lots of things about C are “unintuitive”. Coming from Pascal, I
>>>> found its type-definition syntax completely backwards.
>>>
>>> If only it was simply backwards! Instead it's inside-out and spirular.
>>>
>>> But, yeah, some C aspect being unintuitive is nothing new:
>>>
>>>     extern int abc;
>>>     int abc = 123;
>>>
>>> Or:
>>>
>>>     static int abc;
>>>     extern int abc;
>>>
>>> Both are valid C, but this isn't:
>>>
>>>     extern int abc;
>>>     static int abc;
>>>
>>>
>>> I dare not ask what the rules are; I'm sure they exist, but they
>>> still don't make sense. I can only find out which of these are valid
>>> or not by trial and error. A HLL shouldn't be like that.
>> 
>> Why do you care?
>> As C programmer,
> 
> I'm also an implementer.
> 
>> all you have to know is to never use either 2nd or
>> 3rd, because even if one of them can be legal according to Standard,
>> both of them certainly make no sense.
>> 
>> For your first example, it sometimes make sense, typically as result of
>> #inclyde and/or marcro substitution. What exactly do you find
>> unintuitive about it?
> 
> That you declare 'abc' as something to be imported, yet in the next line 
> it is initialised as though it was exported.

Well, C is not able to directy express notion of export and import.
Also, C does not have modules/interfaces etc.  Instead C object
may be global (which is specified by 'extern' or by lack of storage
class at file scope) or local.  C rules allow you to emulate
modules using header files.  Namely, in header file you put
'extern' declaration for exports of given module.  Any user of
of the module must include the corresponding header file.
To ensure consistency also implementation of the module should
include the header file.  So everywhere elso you have just
'extern' declaration, but in implementation there is 'extern'
declaration first followed by the definition.  If such
sequence was disallowed, then it would be harder to check
consistency of implementation and corresponding header.

So in reasonable code 'extern' really means "part of interface"
without specifying if it is import or export.

Note that implementers of C decided to use system linker.
When C was born standard linkers did not have support for
modules and due to limits on name length emulating such
support was problematic.  So what C did was best thing
possible.  We can now do better, but requirement of
compatibility means that old approach is still in use.
To put it differently: any language which decides to
break compatibility (and a lot did so) can do better than
C.  But due to compatibility C is more popular than
competitors.

-- 
                              Waldek Hebisch

[toc] | [prev] | [next] | [standalone]


#397283

FromBart <bc@freeuk.com>
Date2026-03-29 22:37 +0100
Message-ID<10qc632$1uds9$1@dont-email.me>
In reply to#397260
On 29/03/2026 00:53, Waldek Hebisch wrote:
> Bart <bc@freeuk.com> wrote:

>> That you declare 'abc' as something to be imported, yet in the next line
>> it is initialised as though it was exported.
> 
> Well, C is not able to directy express notion of export and import.
> Also, C does not have modules/interfaces etc.  Instead C object
> may be global (which is specified by 'extern' or by lack of storage
> class at file scope) or local.  C rules allow you to emulate
> modules using header files.  Namely, in header file you put
> 'extern' declaration for exports of given module.  Any user of
> of the module must include the corresponding header file.
> To ensure consistency also implementation of the module should
> include the header file.  So everywhere elso you have just
> 'extern' declaration, but in implementation there is 'extern'
> declaration first followed by the definition.  If such
> sequence was disallowed, then it would be harder to check
> consistency of implementation and corresponding header.
> 
> So in reasonable code 'extern' really means "part of interface"
> without specifying if it is import or export.


But, the rules are lax, and implementations exploit that by all behaving 
a little differently.

TBF, the diverse implementations probably came first, and the standard 
had to accommodate existing practice.

It still means it is lax: you can often get away without using 'extern' 
for example. Or you can define 'int abc' in several modules but the 
linker creates only one definition. (It's stricter now, but tcc for 
example still allows that.)

Still, there aren't really many combinations, and no need to have 
anything more than one definition, and one forward declaration. The 
rules could therefore be simplified, and a compiler could reject 
anything unusual unless specifically enabled.

Here's how it works in my ASM synax:

   F:              # local symbol (a function or variable definition)
   G::             # exported symbol
       call H*     # imported symbol (all instances need the *)

It can be that simple!

(However the assembler allows forward references that C lacks. And there 
is no concept of a shared header; a second module that exports H needs 
to use it locally as H, while calling G needs G*.)

> Note that implementers of C decided to use system linker.
> When C was born standard linkers did not have support for
> modules and due to limits on name length emulating such
> support was problematic.

This is more about namespaces, a separate topic. You can have exported 
and imported symbols without worrying about namespaces, but names may clash.


> So what C did was best thing
> possible.  We can now do better, but requirement of
> compatibility means that old approach is still in use.
> To put it differently: any language which decides to
> break compatibility (and a lot did so) can do better than
> C.  But due to compatibility C is more popular than
> competitors.

Suppose you want to create a DLL or .so file which exports function 'F' 
from this program:

    void F() {}
    void G() {}
    void H() {}

C appears to give no guidance here; the behaviour depends on the compiler:

    gcc:  exports F, G, H
    tcc:  exports none

(With some codebases I've seen which don't bother with 'static', 
hundreds of symbols could be exported.)

This can be changed using an attribute:

    __declspec(dllexport) void F() {}
    void G() {}
    void H() {}

Now:

    gcc:  exports F only (G, H are no longer exported)
    tcc:  exports F

Again, very messy. And ugly.


[toc] | [prev] | [next] | [standalone]


#397303

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-03-30 05:33 -0700
Message-ID<86mrzp1oql.fsf@linuxsc.com>
In reply to#397283
Bart <bc@freeuk.com> writes:

> On 29/03/2026 00:53, Waldek Hebisch wrote:
>
>> Bart <bc@freeuk.com> wrote:
>>
>>> That you declare 'abc' as something to be imported, yet in the next line
>>> it is initialised as though it was exported.
>>
>> Well, C is not able to directy express notion of export and import.
>> Also, C does not have modules/interfaces etc.  Instead C object
>> may be global (which is specified by 'extern' or by lack of storage
>> class at file scope) or local.  C rules allow you to emulate
>> modules using header files.  Namely, in header file you put
>> 'extern' declaration for exports of given module.  Any user of
>> of the module must include the corresponding header file.
>> To ensure consistency also implementation of the module should
>> include the header file.  So everywhere elso you have just
>> 'extern' declaration, but in implementation there is 'extern'
>> declaration first followed by the definition.  If such
>> sequence was disallowed, then it would be harder to check
>> consistency of implementation and corresponding header.
>>
>> So in reasonable code 'extern' really means "part of interface"
>> without specifying if it is import or export.
>
> But, the rules are lax, and implementations exploit that by all
> behaving a little differently.

The rules are not lax;  they are carefully and precisely defined.
To see that one needs to know what the rules are, which in turn
depends on reading and understanding the C standard.

> TBF, the diverse implementations probably came first, and the
> standard had to accommodate existing practice.

Diverse implementations certainly came first, including especially
the original description of C in "The C Programming Language", by
Kernighan and Ritchie.  The rules for global symbols in K&R C are
markedly different than those in the current C standard.  There is
a long explanation of different options considered for standard C,
given in the C Rationale document.

[toc] | [prev] | [next] | [standalone]


#397304

FromBart <bc@freeuk.com>
Date2026-03-30 14:42 +0100
Message-ID<10qdujq$2g7uj$1@dont-email.me>
In reply to#397303
On 30/03/2026 13:33, Tim Rentsch wrote:> Bart <bc@freeuk.com> writes:
 >
 >> On 29/03/2026 00:53, Waldek Hebisch wrote:
 >>
 >>> Bart <bc@freeuk.com> wrote:
 >>>
 >>>> That you declare 'abc' as something to be imported, yet in the 
next line
 >>>> it is initialised as though it was exported.
 >>>
 >>> Well, C is not able to directy express notion of export and import.
 >>> Also, C does not have modules/interfaces etc.  Instead C object
 >>> may be global (which is specified by 'extern' or by lack of storage
 >>> class at file scope) or local.  C rules allow you to emulate
 >>> modules using header files.  Namely, in header file you put
 >>> 'extern' declaration for exports of given module.  Any user of
 >>> of the module must include the corresponding header file.
 >>> To ensure consistency also implementation of the module should
 >>> include the header file.  So everywhere elso you have just
 >>> 'extern' declaration, but in implementation there is 'extern'
 >>> declaration first followed by the definition.  If such
 >>> sequence was disallowed, then it would be harder to check
 >>> consistency of implementation and corresponding header.
 >>>
 >>> So in reasonable code 'extern' really means "part of interface"
 >>> without specifying if it is import or export.
 >>
 >> But, the rules are lax, and implementations exploit that by all
 >> behaving a little differently.
 >
 > The rules are not lax;  they are carefully and precisely defined.
 > To see that one needs to know what the rules are, which in turn
 > depends on reading and understanding the C standard.

The rules may well be precise, but they can also allow for laxity in how 
code is written, and how strictly they are enforced by a compiler.

That is why exactly the same program can pass with 0 warnings or errors, 
pass with some warnings, or fail with errors, depending on the options 
provided. So:

   c:\cx>gcc mcc.c

   c:\cx>gcc -Wall -Wextra -Wpedantic -O2 mcc.c 2>errors

The first invocation compiled fine. The second generated thousands of 
warnings, for the same language standard. With -Werror, it would also fail.

Does the standard also say anything about linking? These two modules:

   a.c:       int abc; int main(){}
   b.c:       int abc;

both individually compile with no problems. They also link successfully 
using TCC and DMC /C/ compilers.

But gcc (invoking its linker) fails saying there are multiple 
definitions of 'abc'.

The point is that a.c + b.c can either form a valid program or not due 
to laxness in the language.

Here's another example which I believe you brought up:

   static void F();
   void F() {}

That first 'static' is what determines F's linkage. However someone 
perusing the source code will see 'void F(){...}` and assume it is exported.

But you can also have:

   static void F(int a);
   static void F(int b);
   static void F(int c);
   extern void F(int d) {}
   static void F(int e);
          void F(int f);
   static void F(int g);

This is what I call being lax, while still within the rules, whatever 
they are.

(In my language, F must be defined in exactly one place. No other 
declarations are allowed or needed within the program itself. So such 
multiple instances don't arise.

It is effectively stricter than C but enforced through better design. 
C's design could also be tightened up, but people don't seem to like 
losing the 'flexibility' shown above.)

[toc] | [prev] | [next] | [standalone]


#397305

FromMichael S <already5chosen@yahoo.com>
Date2026-03-30 16:53 +0300
Message-ID<20260330165336.00006a88@yahoo.com>
In reply to#397304
On Mon, 30 Mar 2026 14:42:18 +0100
Bart <bc@freeuk.com> wrote:

> 
> (In my language, F must be defined in exactly one place. No other 
> declarations are allowed or needed within the program itself. So such 
> multiple instances don't arise.
> 

Do you make distinction between declarations and definitions?

[toc] | [prev] | [next] | [standalone]


#397312

FromBart <bc@freeuk.com>
Date2026-03-30 18:11 +0100
Message-ID<10qeasl$2l5ps$1@dont-email.me>
In reply to#397305
On 30/03/2026 14:53, Michael S wrote:
> On Mon, 30 Mar 2026 14:42:18 +0100
> Bart <bc@freeuk.com> wrote:
> 
>>
>> (In my language, F must be defined in exactly one place. No other
>> declarations are allowed or needed within the program itself. So such
>> multiple instances don't arise.
>>
> 
> Do you make distinction between declarations and definitions?
> 

Yes. Everything within a program will have a definition. No separate 
declarations are needed thanks to the module scheme.

The things that can be defined and shared between modules include 
functions, variables, named constants, enumerations, types, structs, 
macros. Definitions can also be in any order.

Declarations exist, but they are only for things imported from outside 
the program, which will be precompiled external libraries.

This is different from C, where sharing any entity between the modules 
of a program requires each module to see its declaration, while the 
definition resides in some 'home' module.

That can present difficulties, for example:

   char data[];                    # in shared header

   char data[] = {10,20,30,40,50}; # definition

You want to do sizeof(data) from another module, but it doesn't work 
because the size is only known when compiling the home module. Full example:

a.h:
     extern char data[];          // extern is apparently needed

a.c:
     #include <stdio.h>
     #include "a.h"

     char data[] = {10, 20, 30, 40, 50};
     int F();                     // extern is not needed ...

     int main() {printf("%zu\n", F());}

b.c:
     #include "a.h"
     int F() {return sizeof(data);}

Compile using 'cc a.c b.c'. It will complain about sizeof on complete type.

If I try the same thing:

a.m:
     module b
     global []byte data = (10, 20, 30, 40, 50)
     proc main = println F() end

b.m:
     global fun F:int = data.len       # 'fun' is for one-liners

I compile using 'mm a' and it Just Works. I don't even need to tell it 
both module names, or the extension for 'a'. Output is '5'.

Notice here there is one definition for both 'data' and 'F', and no 
declaration. (That 'module b' directive is outside the main language.)

[toc] | [prev] | [next] | [standalone]


#397310

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-03-30 08:27 -0700
Message-ID<865x6d1gnq.fsf@linuxsc.com>
In reply to#397304
Bart <bc@freeuk.com> writes:

> On 30/03/2026 13:33, Tim Rentsch wrote:> Bart <bc@freeuk.com> writes:
>
>>> On 29/03/2026 00:53, Waldek Hebisch wrote:
>>>
>>>> Bart <bc@freeuk.com> wrote:
>>>>
>>>>> That you declare 'abc' as something to be imported, yet in the next line
>>>>> it is initialised as though it was exported.
>>>>
>>>> Well, C is not able to directy express notion of export and import.
>>>> Also, C does not have modules/interfaces etc.  Instead C object
>>>> may be global (which is specified by 'extern' or by lack of storage
>>>> class at file scope) or local.  C rules allow you to emulate
>>>> modules using header files.  Namely, in header file you put
>>>> 'extern' declaration for exports of given module.  Any user of
>>>> of the module must include the corresponding header file.
>>>> To ensure consistency also implementation of the module should
>>>> include the header file.  So everywhere elso you have just
>>>> 'extern' declaration, but in implementation there is 'extern'
>>>> declaration first followed by the definition.  If such
>>>> sequence was disallowed, then it would be harder to check
>>>> consistency of implementation and corresponding header.
>>>>
>>>> So in reasonable code 'extern' really means "part of interface"
>>>> without specifying if it is import or export.
>>>
>>> But, the rules are lax, and implementations exploit that by all
>>> behaving a little differently.
>>
>> The rules are not lax;  they are carefully and precisely defined.
>> To see that one needs to know what the rules are, which in turn
>> depends on reading and understanding the C standard.
>
> The rules may well be precise, but they can also allow for laxity in
> how code is written, and how strictly they are enforced by a compiler.
>
> That is why exactly the same program can pass with 0 warnings or
> errors, pass with some warnings, or fail with errors, depending on the
> options provided.  So:
>
>   c:\cx>gcc mcc.c
>
>   c:\cx>gcc -Wall -Wextra -Wpedantic -O2 mcc.c 2>errors
>
> The first invocation compiled fine.  The second generated thousands of
> warnings, for the same language standard.  With -Werror, it would also
> fail.
>
> Does the standard also say anything about linking?  These two modules:
>
>   a.c:       int abc; int main(){}
>   b.c:       int abc;
>
> both individually compile with no problems.  They also link
> successfully using TCC and DMC /C/ compilers.
>
> But gcc (invoking its linker) fails saying there are multiple
> definitions of 'abc'.
>
> The point is that a.c + b.c can either form a valid program or not due
> to laxness in the language.
>
> Here's another example which I believe you brought up:
>
>   static void F();
>   void F() {}
>
> That first 'static' is what determines F's linkage.  However someone
> perusing the source code will see 'void F(){...}` and assume it is
> exported.
>
> But you can also have:
>
>   static void F(int a);
>   static void F(int b);
>   static void F(int c);
>   extern void F(int d) {}
>   static void F(int e);
>          void F(int f);
>   static void F(int g);
>
> This is what I call being lax, while still within the rules, whatever
> they are.
>
> (In my language, F must be defined in exactly one place.  No other
> declarations are allowed or needed within the program itself.  So such
> multiple instances don't arise.
>
> It is effectively stricter than C but enforced through better
> design.  C's design could also be tightened up, but people don't seem
> to like losing the 'flexibility' shown above.)

It seems to me that your real complaint is not that you don't
understand the rules but that you don't like them.  I'm not able
to help you with that.

[toc] | [prev] | [next] | [standalone]


Page 1 of 4  [1] 2 3 4  Next page →

Back to top | Article view | comp.lang.c


csiph-web