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


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

To include or not to include

Started byJames Harris <james.harris.1@gmail.com>
First post2016-09-23 10:45 +0100
Last post2016-09-23 11:37 -0400
Articles 20 on this page of 70 — 16 participants

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


Contents

  To include or not to include James Harris <james.harris.1@gmail.com> - 2016-09-23 10:45 +0100
    Re: To include or not to include David Brown <david.brown@hesbynett.no> - 2016-09-23 12:43 +0200
      Re: To include or not to include BartC <bc@freeuk.com> - 2016-09-23 12:17 +0100
        Re: To include or not to include Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-23 13:32 +0100
          Re: To include or not to include David Brown <david.brown@hesbynett.no> - 2016-09-23 14:57 +0200
          Re: To include or not to include BartC <bc@freeuk.com> - 2016-09-24 20:34 +0100
            Re: To include or not to include Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-24 23:55 +0100
              Re: To include or not to include BartC <bc@freeuk.com> - 2016-09-25 01:43 +0100
                Re: To include or not to include Ian Collins <ian-news@hotmail.com> - 2016-09-25 14:38 +1300
                Re: To include or not to include Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-25 11:42 +0100
                  Re: To include or not to include BartC <bc@freeuk.com> - 2016-09-25 11:58 +0100
                    Re: To include or not to include James Harris <james.harris.1@gmail.com> - 2016-09-25 14:06 +0100
                      Re: To include or not to include BartC <bc@freeuk.com> - 2016-09-25 15:15 +0100
                        Re: To include or not to include Reinhardt Behm <rbehm@hushmail.com> - 2016-09-25 23:33 +0800
                          Re: To include or not to include Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2016-09-25 10:04 -0600
                            Re: To include or not to include Reinhardt Behm <rbehm@hushmail.com> - 2016-09-26 00:21 +0800
                            Re: To include or not to include "James R. Kuyper" <jameskuyper@verizon.net> - 2016-09-25 13:17 -0400
                        Re: To include or not to include James Harris <james.harris.1@gmail.com> - 2016-09-26 00:18 +0100
                          Re: To include or not to include BartC <bc@freeuk.com> - 2016-09-26 17:55 +0100
                            Re: To include or not to include Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-26 20:07 +0100
                            Re: To include or not to include supercat@casperkitty.com - 2016-09-26 12:13 -0700
                            Re: To include or not to include James Harris <james.harris.1@gmail.com> - 2016-09-27 01:25 +0100
                              Re: To include or not to include supercat@casperkitty.com - 2016-09-26 18:05 -0700
                                Re: To include or not to include Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-27 14:27 +0100
                                  Re: To include or not to include BartC <bc@freeuk.com> - 2016-09-27 14:49 +0100
                                    Re: To include or not to include Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-27 15:15 +0100
                                      Re: To include or not to include Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-27 07:42 -0700
                                        Re: To include or not to include Keith Thompson <kst-u@mib.org> - 2016-09-27 09:30 -0700
                                          Re: To include or not to include Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-27 10:06 -0700
                                      Re: To include or not to include supercat@casperkitty.com - 2016-09-27 08:12 -0700
                                        Re: To include or not to include Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-28 10:46 -0700
                                      Re: To include or not to include BartC <bc@freeuk.com> - 2016-09-27 17:55 +0100
                                        Re: To include or not to include supercat@casperkitty.com - 2016-09-27 10:19 -0700
                                        Re: To include or not to include Keith Thompson <kst-u@mib.org> - 2016-09-27 11:42 -0700
                                          Re: To include or not to include BartC <bc@freeuk.com> - 2016-09-27 19:57 +0100
                                            Re: To include or not to include Keith Thompson <kst-u@mib.org> - 2016-09-27 12:38 -0700
                                              Re: To include or not to include BartC <bc@freeuk.com> - 2016-09-27 21:00 +0100
                                                Re: To include or not to include Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-28 01:50 +0100
                                                  Re: To include or not to include BartC <bc@freeuk.com> - 2016-09-28 10:55 +0100
                                              Re: To include or not to include Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-27 13:33 -0700
                                                Re: To include or not to include Ike Naar <ike@iceland.freeshell.org> - 2016-09-28 19:13 +0000
                                            Re: To include or not to include supercat@casperkitty.com - 2016-09-27 12:38 -0700
                                          Re: To include or not to include James Harris <james.harris.1@gmail.com> - 2016-09-27 20:57 +0100
                                  Re: To include or not to include supercat@casperkitty.com - 2016-09-27 07:25 -0700
                                    Re: To include or not to include Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-28 00:28 +0100
                                      Re: To include or not to include supercat@casperkitty.com - 2016-09-30 07:53 -0700
                                        Re: To include or not to include Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-30 16:06 +0100
                              Re: To include or not to include Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-27 13:53 +0100
                                Re: To include or not to include James Harris <james.harris.1@gmail.com> - 2016-09-30 19:46 +0100
                                  Re: To include or not to include Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-30 20:27 +0100
                      Re: To include or not to include Reinhardt Behm <rbehm@hushmail.com> - 2016-09-25 23:27 +0800
                        Re: To include or not to include Jerry Stuckle <jstucklex@attglobal.net> - 2016-09-25 11:38 -0400
                          Re: To include or not to include Reinhardt Behm <rbehm@hushmail.com> - 2016-09-25 23:40 +0800
                  Re: To include or not to include BartC <bc@freeuk.com> - 2016-09-25 15:06 +0100
                    Re: To include or not to include Jerry Stuckle <jstucklex@attglobal.net> - 2016-09-25 11:49 -0400
                      Re: To include or not to include BartC <bc@freeuk.com> - 2016-09-25 18:05 +0100
                        Re: To include or not to include Jerry Stuckle <jstucklex@attglobal.net> - 2016-09-25 16:42 -0400
                          Re: To include or not to include BartC <bc@freeuk.com> - 2016-09-25 21:53 +0100
                            Re: To include or not to include Jerry Stuckle <jstucklex@attglobal.net> - 2016-09-25 17:57 -0400
                    Re: To include or not to include Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-25 21:20 +0100
                      Re: To include or not to include BartC <bc@freeuk.com> - 2016-09-25 21:49 +0100
                        Re: To include or not to include Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-26 00:40 +0100
        Re: To include or not to include David Brown <david.brown@hesbynett.no> - 2016-09-23 14:56 +0200
    Re: To include or not to include Richard Heathfield <rjh@cpax.org.uk> - 2016-09-23 13:31 +0100
      Re: To include or not to include James Harris <james.harris.1@gmail.com> - 2016-09-23 13:52 +0100
        Re: To include or not to include Richard Heathfield <rjh@cpax.org.uk> - 2016-09-23 14:35 +0100
      Re: To include or not to include Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-23 18:55 +0100
        Re: To include or not to include Richard Heathfield <rjh@cpax.org.uk> - 2016-09-23 20:33 +0100
    Re: To include or not to include Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2016-09-23 08:22 -0600
    Re: To include or not to include Richard Damon <Richard@Damon-Family.org> - 2016-09-23 11:37 -0400

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


#93934 — To include or not to include

FromJames Harris <james.harris.1@gmail.com>
Date2016-09-23 10:45 +0100
SubjectTo include or not to include
Message-ID<ns2tkb$p0$1@dont-email.me>
I often have at the top of a C source file, which I'll call F, an 
include for its corresponding header:

   #include "F.h"

After that come the various includes I need for the .c code that follows.

In many cases the .c and the .h include some of the same files. They 
might both pull in stdio.h or string.h, for example.

Of course, I could omit from F.c at least some of the headers which F.h 
includes. But I tend to take the approach of including in the .c all 
those the .c code needs.

Assuming either approach is just as valid, which is the best style or is 
one more idiomatic than the other?


As an aside, in F.c I include F.h so that the compiler can check that 
function definitions (in F.c) match function declarations (in F.h). So, 
if it's relevant, I guess I tend to use includes as a policy rather than 
as a mechanism for managing other includes.

-- 
James Harris

[toc] | [next] | [standalone]


#93936

FromDavid Brown <david.brown@hesbynett.no>
Date2016-09-23 12:43 +0200
Message-ID<ns310l$bj5$1@dont-email.me>
In reply to#93934
On 23/09/16 11:45, James Harris wrote:
> I often have at the top of a C source file, which I'll call F, an
> include for its corresponding header:
> 
>   #include "F.h"
> 
> After that come the various includes I need for the .c code that follows.
> 
> In many cases the .c and the .h include some of the same files. They
> might both pull in stdio.h or string.h, for example.
> 
> Of course, I could omit from F.c at least some of the headers which F.h
> includes. But I tend to take the approach of including in the .c all
> those the .c code needs.
> 
> Assuming either approach is just as valid, which is the best style or is
> one more idiomatic than the other?
> 
> 
> As an aside, in F.c I include F.h so that the compiler can check that
> function definitions (in F.c) match function declarations (in F.h). So,
> if it's relevant, I guess I tend to use includes as a policy rather than
> as a mechanism for managing other includes.
> 

I prefer the following rules for includes:

1. F.c should include F.h, to make sure that function definitions in F.c
and function declarations in F.h match.

2. I make sure that any functions or file-level variables in F.c are
either defined "static" in F.c, or they are declared "extern" in F.h and
have matching definitions in F.c.

3. Header F.h should include all the headers it needs in order to be
complete.  If G.c includes F.h, it should not have to include anything
else before or after it.  So if F.h declares a function that takes a
uint32_t, then F.h must include stdint.h.

4. Headers should have guards so that you can safely include them many
times.

5. It should be possible to include the headers in any order (this
mostly follows from 3 and 4), both in c and h files.

6. If F.c uses something from G.h, then it should include G.h - even if
F.h already includes G.h.  This is for clarity and self-documentation in
the code.  (Since this is not required for the correctness of the code,
I guess you can count it as "policy rather than mechanism".)


Things can get a lot more complicated with multiple directories, include
paths, combined headers, etc.  But I think they are good rules to start
with.

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


#93937

FromBartC <bc@freeuk.com>
Date2016-09-23 12:17 +0100
Message-ID<ns3316$i3b$1@dont-email.me>
In reply to#93936
On 23/09/2016 11:43, David Brown wrote:
> On 23/09/16 11:45, James Harris wrote:
>> I often have at the top of a C source file, which I'll call F, an
>> include for its corresponding header:
>>
>>   #include "F.h"
>>
>> After that come the various includes I need for the .c code that follows.
>>
>> In many cases the .c and the .h include some of the same files. They
>> might both pull in stdio.h or string.h, for example.
>>
>> Of course, I could omit from F.c at least some of the headers which F.h
>> includes. But I tend to take the approach of including in the .c all
>> those the .c code needs.
>>
>> Assuming either approach is just as valid, which is the best style or is
>> one more idiomatic than the other?
>>
>>
>> As an aside, in F.c I include F.h so that the compiler can check that
>> function definitions (in F.c) match function declarations (in F.h). So,
>> if it's relevant, I guess I tend to use includes as a policy rather than
>> as a mechanism for managing other includes.
>>
>
> I prefer the following rules for includes:
>
> 1. F.c should include F.h, to make sure that function definitions in F.c
> and function declarations in F.h match.
>
> 2. I make sure that any functions or file-level variables in F.c are
> either defined "static" in F.c, or they are declared "extern" in F.h and
> have matching definitions in F.c.
>
> 3. Header F.h should include all the headers it needs in order to be
> complete.  If G.c includes F.h, it should not have to include anything
> else before or after it.  So if F.h declares a function that takes a
> uint32_t, then F.h must include stdint.h.

My rules would be a little different (using example module A):

* A.h should only contain declarations for A.c that will be exported to
   or shared with other modules

* A.h should not contain any includes that are not needed for A.h
   itself. Only includes that are necessary for A.h to compile as a
   standalone file. (For example, including a header that contains
   macros and typedefs used by A.h's declarations)

The rules might be bent a little when looking at a whole project:

* If a project P comprises modules A, B and C, then I might instead
   construct a composite header P.h containing A.h, B.h and C.h.

* Then each of A.c, B.c and C.c includes P.h

* Any external includes (outside of A, B and C) that are used by some or
   all of A, B and C, can also be placed in P.h. Then each module need
   only be headed by a single, common include file.

It can get more complicated if A and B, for example, need to include 
each other's headers; which one is included first in each module? It may 
be necessary to extract items from A.h and B.h that are put into a third 
header (eg. AB.h) that is included before either A.h or B.h (or placed 
before them in P.h).

C allows more elaborate interdependencies still, so it's not possible to 
have rigid rules, only guidelines.

-- 
Bartc

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


#93939

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-09-23 13:32 +0100
Message-ID<87zimyhk54.fsf@bsb.me.uk>
In reply to#93937
BartC <bc@freeuk.com> writes:

> On 23/09/2016 11:43, David Brown wrote:
>> On 23/09/16 11:45, James Harris wrote:
>>> I often have at the top of a C source file, which I'll call F, an
>>> include for its corresponding header:
>>>
>>>   #include "F.h"
>>>
>>> After that come the various includes I need for the .c code that follows.
>>>
>>> In many cases the .c and the .h include some of the same files. They
>>> might both pull in stdio.h or string.h, for example.
>>>
>>> Of course, I could omit from F.c at least some of the headers which F.h
>>> includes. But I tend to take the approach of including in the .c all
>>> those the .c code needs.
>>>
>>> Assuming either approach is just as valid, which is the best style or is
>>> one more idiomatic than the other?
>>>
>>>
>>> As an aside, in F.c I include F.h so that the compiler can check that
>>> function definitions (in F.c) match function declarations (in F.h). So,
>>> if it's relevant, I guess I tend to use includes as a policy rather than
>>> as a mechanism for managing other includes.
>>>
>>
>> I prefer the following rules for includes:
>>
>> 1. F.c should include F.h, to make sure that function definitions in F.c
>> and function declarations in F.h match.
>>
>> 2. I make sure that any functions or file-level variables in F.c are
>> either defined "static" in F.c, or they are declared "extern" in F.h and
>> have matching definitions in F.c.
>>
>> 3. Header F.h should include all the headers it needs in order to be
>> complete.  If G.c includes F.h, it should not have to include anything
>> else before or after it.  So if F.h declares a function that takes a
>> uint32_t, then F.h must include stdint.h.
>
> My rules would be a little different (using example module A):
>
> * A.h should only contain declarations for A.c that will be exported to
>   or shared with other modules
>
> * A.h should not contain any includes that are not needed for A.h
>   itself. Only includes that are necessary for A.h to compile as a
>   standalone file. (For example, including a header that contains
>   macros and typedefs used by A.h's declarations)

In what way is this different?  Do you mean to imply that you *don't*
make sure that A.c includes A.h?  (That's the only thing I can see that
is different, but I assumed it was an omission rather than a rule.)

<snip>
-- 
Ben.

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


#93943

FromDavid Brown <david.brown@hesbynett.no>
Date2016-09-23 14:57 +0200
Message-ID<ns38rb$5u6$2@dont-email.me>
In reply to#93939
On 23/09/16 14:32, Ben Bacarisse wrote:
> BartC <bc@freeuk.com> writes:
> 
>> On 23/09/2016 11:43, David Brown wrote:
>>> On 23/09/16 11:45, James Harris wrote:
>>>> I often have at the top of a C source file, which I'll call F, an
>>>> include for its corresponding header:
>>>>
>>>>   #include "F.h"
>>>>
>>>> After that come the various includes I need for the .c code that follows.
>>>>
>>>> In many cases the .c and the .h include some of the same files. They
>>>> might both pull in stdio.h or string.h, for example.
>>>>
>>>> Of course, I could omit from F.c at least some of the headers which F.h
>>>> includes. But I tend to take the approach of including in the .c all
>>>> those the .c code needs.
>>>>
>>>> Assuming either approach is just as valid, which is the best style or is
>>>> one more idiomatic than the other?
>>>>
>>>>
>>>> As an aside, in F.c I include F.h so that the compiler can check that
>>>> function definitions (in F.c) match function declarations (in F.h). So,
>>>> if it's relevant, I guess I tend to use includes as a policy rather than
>>>> as a mechanism for managing other includes.
>>>>
>>>
>>> I prefer the following rules for includes:
>>>
>>> 1. F.c should include F.h, to make sure that function definitions in F.c
>>> and function declarations in F.h match.
>>>
>>> 2. I make sure that any functions or file-level variables in F.c are
>>> either defined "static" in F.c, or they are declared "extern" in F.h and
>>> have matching definitions in F.c.
>>>
>>> 3. Header F.h should include all the headers it needs in order to be
>>> complete.  If G.c includes F.h, it should not have to include anything
>>> else before or after it.  So if F.h declares a function that takes a
>>> uint32_t, then F.h must include stdint.h.
>>
>> My rules would be a little different (using example module A):
>>
>> * A.h should only contain declarations for A.c that will be exported to
>>   or shared with other modules
>>
>> * A.h should not contain any includes that are not needed for A.h
>>   itself. Only includes that are necessary for A.h to compile as a
>>   standalone file. (For example, including a header that contains
>>   macros and typedefs used by A.h's declarations)
> 
> In what way is this different?  Do you mean to imply that you *don't*
> make sure that A.c includes A.h?  (That's the only thing I can see that
> is different, but I assumed it was an omission rather than a rule.)
> 

As I read it, my rule 3 says A.h should include everything it needs,
while Bart has added that it should not include things it doesn't need.

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


#93990

FromBartC <bc@freeuk.com>
Date2016-09-24 20:34 +0100
Message-ID<ns6kg9$eql$1@dont-email.me>
In reply to#93939
On 23/09/2016 13:32, Ben Bacarisse wrote:
> BartC <bc@freeuk.com> writes:
>> On 23/09/2016 11:43, David Brown wrote:

>>> 1. F.c should include F.h, to make sure that function definitions in F.c
>>> and function declarations in F.h match.
>>>
>>> 2. I make sure that any functions or file-level variables in F.c are
>>> either defined "static" in F.c, or they are declared "extern" in F.h and
>>> have matching definitions in F.c.
>>>
>>> 3. Header F.h should include all the headers it needs in order to be
>>> complete.  If G.c includes F.h, it should not have to include anything
>>> else before or after it.  So if F.h declares a function that takes a
>>> uint32_t, then F.h must include stdint.h.
>>
>> My rules would be a little different (using example module A):
>>
>> * A.h should only contain declarations for A.c that will be exported to
>>   or shared with other modules
>>
>> * A.h should not contain any includes that are not needed for A.h
>>   itself. Only includes that are necessary for A.h to compile as a
>>   standalone file. (For example, including a header that contains
>>   macros and typedefs used by A.h's declarations)
>
> In what way is this different?  Do you mean to imply that you *don't*
> make sure that A.c includes A.h?  (That's the only thing I can see that
> is different, but I assumed it was an omission rather than a rule.)

I didn't see notice No. 2 rule. But I think my rules are stricter.

Looking at the problems that headers need to solve, they aren't actually 
that straightforward. So given this set of names that are defined in 
module A (local or exported in A, or imported elsewhere):

I_local         Local int
J_shared        Exported/Imported int
K_shared        Exported/Imported int (initialised)

A_local         Local array
B_shared        Exported/Imported array
C_shared        Exported/Imported array (initialised)

T_local         Local typedef
U_shared        Exported/Imported typedef

E_local         Local enum and enum names
E_shared        Exported/Imported enum and enum names

M_LOCAL         Local macro
M_SHARED        Exported/Imported macro

F_local         Local function
G_shared        Exported/Imported function

Then A's header A.h might be:
-----------------------
int J_shared;
int K_shared;

int B_shared[10];
int C_shared[];

typedef int U_shared;

enum {xx,yy,zz} E_shared;

#define M_SHARED

void G_shared(int);
-----------------------

while A.c would be:


-----------------------

#include "A.h"

static int I_local;
int K_shared = 1000;

static int A_local[10];
int C_shared[] = {10,20,30};

typedef int T_local;

enum {aa,bb,cc} E_local;

#define M_LOCAL

static void F_local(int);

static void F_local(int a){}

void G_shared(int a){}
-----------------------

Shared functions have to be declared twice (declaration and definition). 
I choose to also have forward declarations for local functions.

Shared variables only need declaring once, unless they are initialised 
then it's easier to declare them twice. (I don't use 'extern' on the 
shared declaration unless forced to by a compiler or linker).

One funny thing about a header such as A.h is that it declares 
*exported* names when compiled as part of A.c, but "imported" names must 
be declared when compiled as part of any other module. All using exactly 
the same syntax.

That's for variables and functions. With typedefs, enums and macros, 
then each module harmlessly declares its own versions.

-- 
Bartc

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


#93998

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-09-24 23:55 +0100
Message-ID<87a8ewgb5y.fsf@bsb.me.uk>
In reply to#93990
BartC <bc@freeuk.com> writes:

> On 23/09/2016 13:32, Ben Bacarisse wrote:
>> BartC <bc@freeuk.com> writes:
>>> On 23/09/2016 11:43, David Brown wrote:
>
>>>> 1. F.c should include F.h, to make sure that function definitions in F.c
>>>> and function declarations in F.h match.
>>>>
>>>> 2. I make sure that any functions or file-level variables in F.c are
>>>> either defined "static" in F.c, or they are declared "extern" in F.h and
>>>> have matching definitions in F.c.
>>>>
>>>> 3. Header F.h should include all the headers it needs in order to be
>>>> complete.  If G.c includes F.h, it should not have to include anything
>>>> else before or after it.  So if F.h declares a function that takes a
>>>> uint32_t, then F.h must include stdint.h.
>>>
>>> My rules would be a little different (using example module A):
>>>
>>> * A.h should only contain declarations for A.c that will be exported to
>>>   or shared with other modules
>>>
>>> * A.h should not contain any includes that are not needed for A.h
>>>   itself. Only includes that are necessary for A.h to compile as a
>>>   standalone file. (For example, including a header that contains
>>>   macros and typedefs used by A.h's declarations)
>>
>> In what way is this different?  Do you mean to imply that you *don't*
>> make sure that A.c includes A.h?  (That's the only thing I can see that
>> is different, but I assumed it was an omission rather than a rule.)
>
> I didn't see notice No. 2 rule. But I think my rules are stricter.
>
> Looking at the problems that headers need to solve, they aren't
> actually that straightforward. So given this set of names that are
> defined in module A (local or exported in A, or imported elsewhere):
>
> I_local         Local int
> J_shared        Exported/Imported int
> K_shared        Exported/Imported int (initialised)
>
> A_local         Local array
> B_shared        Exported/Imported array
> C_shared        Exported/Imported array (initialised)
>
> T_local         Local typedef
> U_shared        Exported/Imported typedef
>
> E_local         Local enum and enum names
> E_shared        Exported/Imported enum and enum names
>
> M_LOCAL         Local macro
> M_SHARED        Exported/Imported macro
>
> F_local         Local function
> G_shared        Exported/Imported function
>
> Then A's header A.h might be:
> -----------------------
> int J_shared;
> int K_shared;
>
> int B_shared[10];
> int C_shared[];
<snip>

> Shared variables only need declaring once, unless they are initialised
> then it's easier to declare them twice. (I don't use 'extern' on the
> shared declaration unless forced to by a compiler or linker).

That's an odd way of putting it.  Alternatively you could say that you
deliberately write undefined code but will correct it if the
implementation happens to say something about it.  Do you take the same
view of any other cases of undefined behaviour?

> One funny thing about a header such as A.h is that it declares
> *exported* names when compiled as part of A.c, but "imported" names
> must be declared when compiled as part of any other module. All using
> exactly the same syntax.

Another funny thing is that it provokes undefined behaviour (when used
as expected).  In effect, it's not really C.  Why would you write it
that way?

-- 
Ben.

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


#94006

FromBartC <bc@freeuk.com>
Date2016-09-25 01:43 +0100
Message-ID<ns76j2$7eh$1@dont-email.me>
In reply to#93998
On 24/09/2016 23:55, Ben Bacarisse wrote:
> BartC <bc@freeuk.com> writes:

>> Then A's header A.h might be:
>> -----------------------
>> int J_shared;
>> int K_shared;
>>
>> int B_shared[10];
>> int C_shared[];
> <snip>
>
>> Shared variables only need declaring once, unless they are initialised
>> then it's easier to declare them twice. (I don't use 'extern' on the
>> shared declaration unless forced to by a compiler or linker).
>
> That's an odd way of putting it.  Alternatively you could say that you
> deliberately write undefined code but will correct it if the
> implementation happens to say something about it.  Do you take the same
> view of any other cases of undefined behaviour?

What's undefined behaviour? Not using 'extern'?

I hardly ever use it (except in generated code; see below), and rarely 
see it used elsewhere. But in my example, I had to use it with 'int 
C_shared[]' when using Tiny C as that compiler didn't like the empty 
array declaration.

>> One funny thing about a header such as A.h is that it declares
>> *exported* names when compiled as part of A.c, but "imported" names
>> must be declared when compiled as part of any other module. All using
>> exactly the same syntax.
>
> Another funny thing is that it provokes undefined behaviour (when used
> as expected).  In effect, it's not really C.  Why would you write it
> that way?

If this is still about 'extern', then it would seem odd writing this in A.h:

   extern int C_shared[];

then a bit later in A.c and so within the same translation unit:

   int C_shared[] = {10,20,30};

So declaring something as external, then defining the very same thing as 
belonging to this module!


(With generated C code, I use a different approach that results in a 
dedicated prelude for each generated C module, rather than explicit 
shared headers.

Then A.c would see 'int C_shared[] = {10,20,30};', but X.c that imports 
A, would see 'extern int C_shared[3];'. But here 'extern' is used in a 
way that makes sense.)

-- 
Bartc

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


#94008

FromIan Collins <ian-news@hotmail.com>
Date2016-09-25 14:38 +1300
Message-ID<e4oo4jFj4bkU1@mid.individual.net>
In reply to#94006
On 09/25/16 01:43 PM, BartC wrote:

> If this is still about 'extern', then it would seem odd writing this in A.h:
>
>     extern int C_shared[];
>
> then a bit later in A.c and so within the same translation unit:
>
>     int C_shared[] = {10,20,30};
>
> So declaring something as external, then defining the very same thing as
> belonging to this module!
>
>
> (With generated C code, I use a different approach that results in a
> dedicated prelude for each generated C module, rather than explicit
> shared headers.
>
> Then A.c would see 'int C_shared[] = {10,20,30};', but X.c that imports
> A, would see 'extern int C_shared[3];'. But here 'extern' is used in a
> way that makes sense.)

Every compilation unit that includes A.h and uses C_shared has to see 
the extern declaration, including the one with the definition.

-- 
Ian

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


#94017

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-09-25 11:42 +0100
Message-ID<87r388dzw9.fsf@bsb.me.uk>
In reply to#94006
BartC <bc@freeuk.com> writes:

> On 24/09/2016 23:55, Ben Bacarisse wrote:
>> BartC <bc@freeuk.com> writes:
>
>>> Then A's header A.h might be:
>>> -----------------------
>>> int J_shared;
>>> int K_shared;
>>>
>>> int B_shared[10];
>>> int C_shared[];
>> <snip>
>>
>>> Shared variables only need declaring once, unless they are initialised
>>> then it's easier to declare them twice. (I don't use 'extern' on the
>>> shared declaration unless forced to by a compiler or linker).
>>
>> That's an odd way of putting it.  Alternatively you could say that you
>> deliberately write undefined code but will correct it if the
>> implementation happens to say something about it.  Do you take the same
>> view of any other cases of undefined behaviour?
>
> What's undefined behaviour? Not using 'extern'?

Not exactly.  It's having multiple definitions for the some identifier
with external linkage.  extern can be used to prevent that.

> I hardly ever use it (except in generated code; see below), and rarely
> see it used elsewhere.

I'd hope not.  After decades of education, I would hope that programs
that rely on "global" data objects are getting increasingly rare.  If
you mean that don't see it used when it should be used, that's another
matter.

> But in my example, I had to use it with 'int
> C_shared[]' when using Tiny C as that compiler didn't like the empty
> array declaration.

It's a tentative *defintiion* with an incomplete type.  At the end of
the translation unit it should be processed as if it had been written

  int C_shared[] = {0};

>>> One funny thing about a header such as A.h is that it declares
>>> *exported* names when compiled as part of A.c, but "imported" names
>>> must be declared when compiled as part of any other module. All using
>>> exactly the same syntax.
>>
>> Another funny thing is that it provokes undefined behaviour (when used
>> as expected).  In effect, it's not really C.  Why would you write it
>> that way?
>
> If this is still about 'extern', then it would seem odd writing this in A.h:
>
>   extern int C_shared[];
>
> then a bit later in A.c and so within the same translation unit:
>
>   int C_shared[] = {10,20,30};
>
> So declaring something as external, then defining the very same thing
> as belonging to this module!

What a joy for you.  C has the power to amaze you with some new oddity
every day.

<snip>
-- 
Ben.

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


#94020

FromBartC <bc@freeuk.com>
Date2016-09-25 11:58 +0100
Message-ID<ns8akc$o3j$1@dont-email.me>
In reply to#94017
On 25/09/2016 11:42, Ben Bacarisse wrote:
> BartC <bc@freeuk.com> writes:

>> If this is still about 'extern', then it would seem odd writing this in A.h:
>>
>>   extern int C_shared[];
>>
>> then a bit later in A.c and so within the same translation unit:
>>
>>   int C_shared[] = {10,20,30};
>>
>> So declaring something as external, then defining the very same thing
>> as belonging to this module!
>
> What a joy for you.  C has the power to amaze you with some new oddity
> every day.

It's not just about me. It's illogical and confusing. If I write this in 
Nasm:

       extern bart
bart:

it says symbol 'bart' is redefined.

I thought C was supposed to be higher level than such languages?

The C method does solve one problem (having a single form of declaration 
that works in both exporting and importing modules, rather than needing 
two), but it is not satisfactory.

-- 
Bartc

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


#94023

FromJames Harris <james.harris.1@gmail.com>
Date2016-09-25 14:06 +0100
Message-ID<ns8i3i$fks$1@dont-email.me>
In reply to#94020
On 25/09/2016 11:58, BartC wrote:
> On 25/09/2016 11:42, Ben Bacarisse wrote:
>> BartC <bc@freeuk.com> writes:
>
>>> If this is still about 'extern', then it would seem odd writing this
>>> in A.h:
>>>
>>>   extern int C_shared[];
>>>
>>> then a bit later in A.c and so within the same translation unit:
>>>
>>>   int C_shared[] = {10,20,30};
>>>
>>> So declaring something as external, then defining the very same thing
>>> as belonging to this module!
>>
>> What a joy for you.  C has the power to amaze you with some new oddity
>> every day.
>
> It's not just about me. It's illogical and confusing. If I write this in
> Nasm:
>
>       extern bart
> bart:
>
> it says symbol 'bart' is redefined.
>
> I thought C was supposed to be higher level than such languages?

Some of C's rules are for compatibility.

Besides, are you interpreting the extern keyword incorrectly. It does 
not mean what it does in Nasm. IIRC it does not mean "external to this 
translation unit".

Wouldn't it be more accurate to say that it means "external to a function"?


> The C method does solve one problem (having a single form of declaration
> that works in both exporting and importing modules, rather than needing
> two), but it is not satisfactory.

I think the issue is that extern declarations are often placed in header 
files. It is convenient for the same headers to be #included in the 
clients as well as the provider.

For example, imagine you had a program fred.c with a fred.h header and 
fred.c had a global (i.e. exported) symbol mary. Then, fred.h would have

   extern int mary ....

That header is also #included in fred.c so the compiler could see

   int mary ....
   extern int mary ....

C allows them both to appear in the same TU. Perhaps at the file level 
extern could be seen as a sort of tentative declaration....?


-- 
James Harris

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


#94025

FromBartC <bc@freeuk.com>
Date2016-09-25 15:15 +0100
Message-ID<ns8m5r$sqi$1@dont-email.me>
In reply to#94023
On 25/09/2016 14:06, James Harris wrote:
> On 25/09/2016 11:58, BartC wrote:

>> It's not just about me. It's illogical and confusing. If I write this in
>> Nasm:
>>
>>       extern bart
>> bart:
>>
>> it says symbol 'bart' is redefined.
>>
>> I thought C was supposed to be higher level than such languages?
>
> Some of C's rules are for compatibility.
>
> Besides, are you interpreting the extern keyword incorrectly. It does
> not mean what it does in Nasm. IIRC it does not mean "external to this
> translation unit".
>
> Wouldn't it be more accurate to say that it means "external to a function"?

Yes, I remember now that this came up before; extern means external to a 
function (and a new entry for my list of quirks!).

In which case it's surprising you don't see it more often, in front of 
function declarations definitions for example. The answer is that most 
such 'extern' names are obviously external-to-functions by context (ie. 
placement).

So it seems superfluous. Unless, for some bizarre reason, you want to 
actually declare a file-scope name inside a function.

And it doesn't really explain however why 'extern' needs to be used for 
names of file-scope objects and functions that are shared between modules.

-- 
Bartc

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


#94027

FromReinhardt Behm <rbehm@hushmail.com>
Date2016-09-25 23:33 +0800
Message-ID<ns8qnt$c3b$1@dont-email.me>
In reply to#94025
AT Sunday 25 September 2016 22:15, BartC wrote:

> On 25/09/2016 14:06, James Harris wrote:
>> On 25/09/2016 11:58, BartC wrote:
> 
>>> It's not just about me. It's illogical and confusing. If I write this in
>>> Nasm:
>>>
>>>       extern bart
>>> bart:
>>>
>>> it says symbol 'bart' is redefined.
>>>
>>> I thought C was supposed to be higher level than such languages?
>>
>> Some of C's rules are for compatibility.
>>
>> Besides, are you interpreting the extern keyword incorrectly. It does
>> not mean what it does in Nasm. IIRC it does not mean "external to this
>> translation unit".
>>
>> Wouldn't it be more accurate to say that it means "external to a
>> function"?
> 
> Yes, I remember now that this came up before; extern means external to a
> function (and a new entry for my list of quirks!).
> 
> In which case it's surprising you don't see it more often, in front of
> function declarations definitions for example. The answer is that most
> such 'extern' names are obviously external-to-functions by context (ie.
> placement).
> 
> So it seems superfluous. Unless, for some bizarre reason, you want to
> actually declare a file-scope name inside a function.
> 
> And it doesn't really explain however why 'extern' needs to be used for
> names of file-scope objects and functions that are shared between modules.

The interpretation "extern to a function" does not make sense. A static 
declaration in file scope is also "extern to a function" but not known 
outside the compilation unit.
 
-- 
Reinhardt

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


#94033

FromJoe Pfeiffer <pfeiffer@cs.nmsu.edu>
Date2016-09-25 10:04 -0600
Message-ID<1b7fa0kltw.fsf@pfeifferfamily.net>
In reply to#94027
Reinhardt Behm <rbehm@hushmail.com> writes:

> AT Sunday 25 September 2016 22:15, BartC wrote:
>
>> On 25/09/2016 14:06, James Harris wrote:
>>> On 25/09/2016 11:58, BartC wrote:
>> 
>>>> It's not just about me. It's illogical and confusing. If I write this in
>>>> Nasm:
>>>>
>>>>       extern bart
>>>> bart:
>>>>
>>>> it says symbol 'bart' is redefined.
>>>>
>>>> I thought C was supposed to be higher level than such languages?
>>>
>>> Some of C's rules are for compatibility.
>>>
>>> Besides, are you interpreting the extern keyword incorrectly. It does
>>> not mean what it does in Nasm. IIRC it does not mean "external to this
>>> translation unit".
>>>
>>> Wouldn't it be more accurate to say that it means "external to a
>>> function"?
>> 
>> Yes, I remember now that this came up before; extern means external to a
>> function (and a new entry for my list of quirks!).
>> 
>> In which case it's surprising you don't see it more often, in front of
>> function declarations definitions for example. The answer is that most
>> such 'extern' names are obviously external-to-functions by context (ie.
>> placement).
>> 
>> So it seems superfluous. Unless, for some bizarre reason, you want to
>> actually declare a file-scope name inside a function.
>> 
>> And it doesn't really explain however why 'extern' needs to be used for
>> names of file-scope objects and functions that are shared between modules.
>
> The interpretation "extern to a function" does not make sense. A static 
> declaration in file scope is also "extern to a function" but not known 
> outside the compilation unit.

It may not make sense, but here's what the standard says (6.9, point 4):
    As discussed in 5.1.1.1, the unit of program text after
    preprocessing is a translation unit, which consists of a sequence of
    external declarations. These are described as "external" because
    they appear outside any function (and hence have file scope).

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


#94034

FromReinhardt Behm <rbehm@hushmail.com>
Date2016-09-26 00:21 +0800
Message-ID<ns8thv$jj3$3@dont-email.me>
In reply to#94033
AT Monday 26 September 2016 00:04, Joe Pfeiffer wrote:

> Reinhardt Behm <rbehm@hushmail.com> writes:
> 
>> AT Sunday 25 September 2016 22:15, BartC wrote:
>>
>>> On 25/09/2016 14:06, James Harris wrote:
>>>> On 25/09/2016 11:58, BartC wrote:
>>> 
>>>>> It's not just about me. It's illogical and confusing. If I write this
>>>>> in Nasm:
>>>>>
>>>>>       extern bart
>>>>> bart:
>>>>>
>>>>> it says symbol 'bart' is redefined.
>>>>>
>>>>> I thought C was supposed to be higher level than such languages?
>>>>
>>>> Some of C's rules are for compatibility.
>>>>
>>>> Besides, are you interpreting the extern keyword incorrectly. It does
>>>> not mean what it does in Nasm. IIRC it does not mean "external to this
>>>> translation unit".
>>>>
>>>> Wouldn't it be more accurate to say that it means "external to a
>>>> function"?
>>> 
>>> Yes, I remember now that this came up before; extern means external to a
>>> function (and a new entry for my list of quirks!).
>>> 
>>> In which case it's surprising you don't see it more often, in front of
>>> function declarations definitions for example. The answer is that most
>>> such 'extern' names are obviously external-to-functions by context (ie.
>>> placement).
>>> 
>>> So it seems superfluous. Unless, for some bizarre reason, you want to
>>> actually declare a file-scope name inside a function.
>>> 
>>> And it doesn't really explain however why 'extern' needs to be used for
>>> names of file-scope objects and functions that are shared between
>>> modules.
>>
>> The interpretation "extern to a function" does not make sense. A static
>> declaration in file scope is also "extern to a function" but not known
>> outside the compilation unit.
> 
> It may not make sense, but here's what the standard says (6.9, point 4):
>     As discussed in 5.1.1.1, the unit of program text after
>     preprocessing is a translation unit, which consists of a sequence of
>     external declarations. These are described as "external" because
>     they appear outside any function (and hence have file scope).

It may be the word (not even that it's "external" against "extern") but this 
has not much to do with what has been discussed her.

-- 
Reinhardt

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


#94039

From"James R. Kuyper" <jameskuyper@verizon.net>
Date2016-09-25 13:17 -0400
Message-ID<f923c0cc-7729-e4b9-1673-f9afa6ef19ca@verizon.net>
In reply to#94033
On 09/25/2016 12:04 PM, Joe Pfeiffer wrote:
...
> It may not make sense, but here's what the standard says (6.9, point 4):
>     As discussed in 5.1.1.1, the unit of program text after
>     preprocessing is a translation unit, which consists of a sequence of
>     external declarations. These are described as "external" because
>     they appear outside any function (and hence have file scope).

The word "external" in "external declarations" is not directly connected 
to the same word when used in the term "external linkage". Anything with 
external linkage must have an external declaration, but not all external 
declarations have external linkage. This is another case where C's 
jargon is less than ideal.

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


#94063

FromJames Harris <james.harris.1@gmail.com>
Date2016-09-26 00:18 +0100
Message-ID<ns9m0h$fij$1@dont-email.me>
In reply to#94025
On 25/09/2016 15:15, BartC wrote:
> On 25/09/2016 14:06, James Harris wrote:
>> On 25/09/2016 11:58, BartC wrote:
>
>>> It's not just about me. It's illogical and confusing. If I write this in
>>> Nasm:
>>>
>>>       extern bart
>>> bart:
>>>
>>> it says symbol 'bart' is redefined.
>>>
>>> I thought C was supposed to be higher level than such languages?
>>
>> Some of C's rules are for compatibility.
>>
>> Besides, are you interpreting the extern keyword incorrectly. It does
>> not mean what it does in Nasm. IIRC it does not mean "external to this
>> translation unit".
>>
>> Wouldn't it be more accurate to say that it means "external to a
>> function"?
>
> Yes, I remember now that this came up before; extern means external to a
> function (and a new entry for my list of quirks!).
>
> In which case it's surprising you don't see it more often, in front of
> function declarations definitions for example. The answer is that most
> such 'extern' names are obviously external-to-functions by context (ie.
> placement).
>
> So it seems superfluous. Unless, for some bizarre reason, you want to
> actually declare a file-scope name inside a function.

IIRC this goes back to support for single pass. Consider this code:

   int x = 1;
   int f(void) {
     return x;
   }

When the compiler gets to see x in the function it knows its type.

Now imagine that the definition of x is placed after f(). In that case, 
extern would be needed, as in

   int f(void) {
     extern int x;
     return x;
   }
   int x = 1;

In this case, the extern tells the compiler the type of x. If it did not 
then it would not know the type when it needed to.

Because we normally declare external variables at file scope /before/ 
functions we don't normally need such uses of extern.

> And it doesn't really explain however why 'extern' needs to be used for
> names of file-scope objects and functions that are shared between modules.

 From memory I think this is a subtle difference between declarations 
(i.e. setting type information) and definitions (reserving storage). 
Consider at file scope

   int x;

Even though that does not assign a value, IIRC the compiler might treat 
it as a definition (rules as to when are fiddly). But compare that with

   extern int x;

The compiler will always see that as a declaration (again, with very 
fiddly rules) and not a definition.

Oversimplification: Maybe extern declares without reserving storage, 
even at file scope.

I fully expect to be criticised mercilessly for the above description...!

-- 
James Harris

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


#94095

FromBartC <bc@freeuk.com>
Date2016-09-26 17:55 +0100
Message-ID<nsbju0$4vl$1@dont-email.me>
In reply to#94063
On 26/09/2016 00:18, James Harris wrote:
> On 25/09/2016 15:15, BartC wrote:

>> So it seems superfluous. Unless, for some bizarre reason, you want to
>> actually declare a file-scope name inside a function.
>
> IIRC this goes back to support for single pass. Consider this code:
>
>   int x = 1;
>   int f(void) {
>     return x;
>   }
>
> When the compiler gets to see x in the function it knows its type.

Presumably single passes are still used because C still has trouble with 
references to functions and variables that occur later on. (Or more 
likely, it has to maintain that behaviour even though forward 
declaration requirements could easily be relaxed.)

>> And it doesn't really explain however why 'extern' needs to be used for
>> names of file-scope objects and functions that are shared between
>> modules.
>
> From memory I think this is a subtle difference between declarations
> (i.e. setting type information) and definitions (reserving storage).
> Consider at file scope
>
>   int x;
>
> Even though that does not assign a value, IIRC the compiler might treat
> it as a definition (rules as to when are fiddly). But compare that with
>
>   extern int x;
>
> The compiler will always see that as a declaration (again, with very
> fiddly rules) and not a definition.

All C compilers I've tried have no problem with:

     int x;
     int x;
     int x;
     int x;
     int x;

within the same module, provided only one is initialised.

Even when some of these are in other modules: the linker sees multiple 
instances and creates only one. EXCEPT when I use Tiny C, then it will 
report multiple definitions of x. That can be fixed by using extern in 
all either modules except one or even when extern is used everywhere.

I don't know if that's a problem with Tiny C, or if it's all the other 
compilers that are being lax.

> Oversimplification: Maybe extern declares without reserving storage,
> even at file scope.

But as I said, you can use only extern, and it will still reserve storage.

> I fully expect to be criticised mercilessly for the above description...!

Actually I don't think even the C experts know exactly how it works half 
the time!

-- 
Bartc

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


#94098

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-09-26 20:07 +0100
Message-ID<87k2dycweu.fsf@bsb.me.uk>
In reply to#94095
BartC <bc@freeuk.com> writes:

> On 26/09/2016 00:18, James Harris wrote:
>> On 25/09/2016 15:15, BartC wrote:
>
>>> So it seems superfluous. Unless, for some bizarre reason, you want to
>>> actually declare a file-scope name inside a function.
>>
>> IIRC this goes back to support for single pass. Consider this code:
>>
>>   int x = 1;
>>   int f(void) {
>>     return x;
>>   }
>>
>> When the compiler gets to see x in the function it knows its type.
>
> Presumably single passes are still used because C still has trouble
> with references to functions and variables that occur later on. (Or
> more likely, it has to maintain that behaviour even though forward
> declaration requirements could easily be relaxed.)
>
>>> And it doesn't really explain however why 'extern' needs to be used for
>>> names of file-scope objects and functions that are shared between
>>> modules.
>>
>> From memory I think this is a subtle difference between declarations
>> (i.e. setting type information) and definitions (reserving storage).
>> Consider at file scope
>>
>>   int x;
>>
>> Even though that does not assign a value, IIRC the compiler might treat
>> it as a definition (rules as to when are fiddly). But compare that with
>>
>>   extern int x;
>>
>> The compiler will always see that as a declaration (again, with very
>> fiddly rules) and not a definition.
>
> All C compilers I've tried have no problem with:
>
>     int x;
>     int x;
>     int x;
>     int x;
>     int x;

All conforming C compilers must have no problem with this.

> within the same module, provided only one is initialised.

I'd say "at file scope in the same translation unit, provided no more
than one is initialised".  These are all what are call tentative
definitions.  The syntax is there because of the long, deep history of
C.  I doubt anyone would design it this way if starting from scratch.

> Even when some of these are in other modules: the linker sees multiple
> instances and creates only one.

If some appear in other translation units (C does not have modules), the
result is undefined (as I said before).

> EXCEPT when I use Tiny C, then it will
> report multiple definitions of x. That can be fixed by using extern in
> all either modules except one or even when extern is used everywhere.

Using extern everywhere fixes nothing -- it only "works" if the object
is not used since it prevents there being any definition of it.

> I don't know if that's a problem with Tiny C, or if it's all the other
> compilers that are being lax.

With gcc you are, implicitly, asking for this behaviour because gcc's
default behaviour is to place such objects into a common block.  You can
stop this by using -fno-common, in which case the linker will complain
about the multiple definitions.  All of these behaviours are conforming.

<snip>
-- 
Ben.

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


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

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


csiph-web