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


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

Question about use (and non-use) of "extern"

Started bygazelle@shell.xmission.com (Kenny McCormack)
First post2019-08-20 13:11 +0000
Last post2019-09-06 20:24 +0200
Articles 20 on this page of 42 — 15 participants

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


Contents

  Question about use (and non-use) of "extern" gazelle@shell.xmission.com (Kenny McCormack) - 2019-08-20 13:11 +0000
    Re: Question about use (and non-use) of "extern" David Brown <david.brown@hesbynett.no> - 2019-08-20 16:09 +0200
    Re: Question about use (and non-use) of "extern" Bart <bc@freeuk.com> - 2019-08-20 16:41 +0100
      Re: Question about use (and non-use) of "extern" Bart <bc@freeuk.com> - 2019-08-20 16:47 +0100
      Re: Question about use (and non-use) of "extern" David Brown <david.brown@hesbynett.no> - 2019-08-20 19:27 +0200
        Re: Question about use (and non-use) of "extern" Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2019-08-20 13:54 -0400
          Re: Question about use (and non-use) of "extern" Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-08-21 02:09 +0100
          Re: Question about use (and non-use) of "extern" David Brown <david.brown@hesbynett.no> - 2019-08-21 10:54 +0200
        Re: Question about use (and non-use) of "extern" Bart <bc@freeuk.com> - 2019-08-21 00:41 +0100
          Re: Question about use (and non-use) of "extern" David Brown <david.brown@hesbynett.no> - 2019-08-21 10:58 +0200
    Re: Question about use (and non-use) of "extern" richard@cogsci.ed.ac.uk (Richard Tobin) - 2019-08-20 16:10 +0000
      Re: Question about use (and non-use) of "extern" Siri Cruise <chine.bleu@yahoo.com> - 2019-08-20 16:23 -0700
    Re: Question about use (and non-use) of "extern" already5chosen@yahoo.com - 2019-08-21 06:50 -0700
      Re: Question about use (and non-use) of "extern" gazelle@shell.xmission.com (Kenny McCormack) - 2019-08-22 20:20 +0000
        Re: Question about use (and non-use) of "extern" David Brown <david.brown@hesbynett.no> - 2019-08-23 00:25 +0200
        Re: Question about use (and non-use) of "extern" Bart <bc@freeuk.com> - 2019-08-23 01:35 +0100
          Re: Question about use (and non-use) of "extern" gazelle@shell.xmission.com (Kenny McCormack) - 2019-08-23 03:40 +0000
            Re: Question about use (and non-use) of "extern" Bart <bc@freeuk.com> - 2019-08-23 11:09 +0100
          Re: Question about use (and non-use) of "extern" David Brown <david.brown@hesbynett.no> - 2019-08-23 08:16 +0200
        Re: Question about use (and non-use) of "extern" scott@slp53.sl.home (Scott Lurndal) - 2019-08-23 15:02 +0000
          Re: Question about use (and non-use) of "extern" Bart <bc@freeuk.com> - 2019-08-23 17:06 +0100
            Re: Question about use (and non-use) of "extern" gazelle@shell.xmission.com (Kenny McCormack) - 2019-08-23 18:40 +0000
            Re: Question about use (and non-use) of "extern" scott@slp53.sl.home (Scott Lurndal) - 2019-08-23 20:38 +0000
              Re: Question about use (and non-use) of "extern" Richard Damon <Richard@Damon-Family.org> - 2019-08-23 17:55 -0400
                Richard Damon weighs in... (Was: Question about use (and non-use) of "extern") gazelle@shell.xmission.com (Kenny McCormack) - 2019-08-23 23:50 +0000
    Re: Question about use (and non-use) of "extern" Andrey Tarasevich <andreytarasevich@hotmail.com> - 2019-08-27 15:03 -0700
      Re: Question about use (and non-use) of "extern" Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-09-03 05:57 -0700
        Re: Question about use (and non-use) of "extern" David Brown <david.brown@hesbynett.no> - 2019-09-03 15:45 +0200
          Re: Question about use (and non-use) of "extern" Keith Thompson <kst-u@mib.org> - 2019-09-03 11:13 -0700
            Re: Question about use (and non-use) of "extern" David Brown <david.brown@hesbynett.no> - 2019-09-04 12:11 +0200
              Re: Question about use (and non-use) of "extern" James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-09-04 08:18 -0400
            Re: Question about use (and non-use) of "extern" Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-09-06 02:25 -0700
              Re: Question about use (and non-use) of "extern" David Brown <david.brown@hesbynett.no> - 2019-09-06 11:45 +0200
            Re: Question about use (and non-use) of "extern" Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-09-06 21:15 +0100
          Re: Question about use (and non-use) of "extern" James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-09-03 21:10 -0400
            Re: Question about use (and non-use) of "extern" David Brown <david.brown@hesbynett.no> - 2019-09-04 12:21 +0200
        Re: Question about use (and non-use) of "extern" Andrey Tarasevich <andreytarasevich@hotmail.com> - 2019-09-04 12:04 -0700
          Re: Question about use (and non-use) of "extern" James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-09-04 15:29 -0400
          Re: Question about use (and non-use) of "extern" Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-09-06 02:46 -0700
    Re: Question about use (and non-use) of "extern" Bonita Montero <Bonita.Montero@gmail.com> - 2019-09-05 10:01 +0200
      Re: Question about use (and non-use) of "extern" Andrey Tarasevich <andreytarasevich@hotmail.com> - 2019-09-05 10:43 -0700
        Re: Question about use (and non-use) of "extern" Bonita Montero <Bonita.Montero@gmail.com> - 2019-09-06 20:24 +0200

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


#145732 — Question about use (and non-use) of "extern"

Fromgazelle@shell.xmission.com (Kenny McCormack)
Date2019-08-20 13:11 +0000
SubjectQuestion about use (and non-use) of "extern"
Message-ID<qjgric$8u2$1@news.xmission.com>
Suppose you have multiple source files and you want to share access to a
global (see footnote) variable.  The usual method is to define it in one
module and "extern" it everywhere else.  E.g.:

/* In one module */
int i;

/* Everywhere else */
extern int i;

But what happens if you break this pattern?  I've determined that:

1) If you "extern" it everywhere, you get "undefined variable" errors.

2) If you "extern" it nowhere, it works fine.

My question is: Is the later case OK?  Is it OK to just declare it normally
in every module and not bother with "extern" ?

I remember reading somewhere long ago that historically this works, but
that it isn't guaranteed.

Footnote: Uh, oh.  I said "the 'g' word"...

-- 
"We should always be disposed to believe that which appears to us to be
white is really black, if the hierarchy  of the church so decides." 

    - Saint Ignatius Loyola (1491-1556) Founder of the Jesuit Order -

[toc] | [next] | [standalone]


#145733

FromDavid Brown <david.brown@hesbynett.no>
Date2019-08-20 16:09 +0200
Message-ID<qjguvf$fe3$1@dont-email.me>
In reply to#145732
On 20/08/2019 15:11, Kenny McCormack wrote:
> Suppose you have multiple source files and you want to share access to a
> global (see footnote) variable.  The usual method is to define it in one
> module and "extern" it everywhere else.  E.g.:
> 
> /* In one module */
> int i;
> 
> /* Everywhere else */
> extern int i;

A better habit is to have:

// module.h
extern int i;

// module.c
#include "module.h"

int i;

// other.c
#include "module.h"


I get highly suspicious any time I see an "extern" in a C file.  I get
even more suspicious any time I see an object declaration in a header
that is not an "extern" or a "static" (usually "static const").

> 
> But what happens if you break this pattern?  I've determined that:
> 
> 1) If you "extern" it everywhere, you get "undefined variable" errors.
> 

Of course.  "extern" gives you a declaration for the variable, but not a
definition.  It must be /defined/ somewhere too - exactly once in the
program, without "extern" (or "static").

> 2) If you "extern" it nowhere, it works fine.

No, it doesn't work "fine".  It will work on some implementations and
not others.  Many implementations put definitions like "int i;" into
"common" segments, and then combine any items there with the same name.
 Some programming languages (like FORTRAN) need this - others, like C,
do not.  But linkers and compilers often supported it because the same
tools are used for FORTRAN.  Then some C programmers got in the bad
habit of thinking it is supported, and thus C compilers had to support
it for backwards compatibility with existing C.  So we get a vicious
circle of a bad programming practice.

Key problems with this approach are you get breakages if the variable is
initialised somewhere ("int i = 123;"), and you get "fun" problems if
you use the same name for other purposes (like "double i;") in different
files.  Generally these things are not diagnosed at compile or link
time, and good luck finding them in testing.

Another issue is that the resulting code is less efficient.

So my advice is just say "no" to common variables - "gcc -fno-common".

> 
> My question is: Is the later case OK?  Is it OK to just declare it normally
> in every module and not bother with "extern" ?
> 
> I remember reading somewhere long ago that historically this works, but
> that it isn't guaranteed.

You read it again here!

> 
> Footnote: Uh, oh.  I said "the 'g' word"...
> 

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


#145734

FromBart <bc@freeuk.com>
Date2019-08-20 16:41 +0100
Message-ID<TwU6F.128430$GfB1.77778@fx36.am4>
In reply to#145732
On 20/08/2019 14:11, Kenny McCormack wrote:
> Suppose you have multiple source files and you want to share access to a
> global (see footnote) variable.  The usual method is to define it in one
> module and "extern" it everywhere else.  E.g.:
> 
> /* In one module */
> int i;
> 
> /* Everywhere else */
> extern int i;
> 
> But what happens if you break this pattern?  I've determined that:
> 
> 1) If you "extern" it everywhere, you get "undefined variable" errors.

Not with my C compiler, as each module will then expect to import it 
from elsewhere, but no other module will export it, so 'i' is undefined 
at the link stage.

> 2) If you "extern" it nowhere, it works fine.

Again, not with my C compiler. Without extern and without static, each 
'int i' is defined in each module then exported. You get multiple 
definitions.

Some compilers' linkers will take care of that, provided not more than 
one 'i' is initialised, and reduce multiple instances to 1, or with zero 
instances, somehow magic one instance out of nowhere, and belonging to 
no module.

That encourages sloppiness which one day will bite (like a lot of things 
with C that I find sloppy).

It also means that to the reader who needs to maintain the code, how 
will they know which module 'owns' the variable, or which module exports it?

> 
> My question is: Is the later case OK?  Is it OK to just declare it normally
> in every module and not bother with "extern" ?

If not using shared headers but ad-hoc declarations in each module:

(1) Decide which module should export the variable, and declare it as:

     int i;           // with optional initial value

     in that module;

(2) In all other modules, declare it as:

     extern int i;


If using a shared header, then declare it as

    extern int i;

in that header, which is included by all the modules (that can include 
the one exporting it). In the module exporting it, declare as:

    int i;        // optional init

If this module includes the header, it will see both 'extern int i' and 
'int i', but that's OK; the latter exporting declaration takes priority.

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


#145735

FromBart <bc@freeuk.com>
Date2019-08-20 16:47 +0100
Message-ID<8CU6F.322032$dw4.256852@fx12.am4>
In reply to#145734
On 20/08/2019 16:41, Bart wrote:

>> 1) If you "extern" it everywhere, you get "undefined variable" errors.
> 
> Not with my C compiler

Scrap that. Somehow I thought you were saying that that worked.

> or with zero 
> instances, somehow magic one instance out of nowhere, and belonging to 
> no module.

And this. It seems most compilers are find with 1 or more global 
instances of a name, but it can't be 0. Mine needs exactly 1.

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


#145737

FromDavid Brown <david.brown@hesbynett.no>
Date2019-08-20 19:27 +0200
Message-ID<qjhahd$nq1$1@dont-email.me>
In reply to#145734
On 20/08/2019 17:41, Bart wrote:
> On 20/08/2019 14:11, Kenny McCormack wrote:
>> Suppose you have multiple source files and you want to share access to a
>> global (see footnote) variable.  The usual method is to define it in one
>> module and "extern" it everywhere else.  E.g.:
>>
>> /* In one module */
>> int i;
>>
>> /* Everywhere else */
>> extern int i;
>>
>> But what happens if you break this pattern?  I've determined that:
>>
>> 1) If you "extern" it everywhere, you get "undefined variable" errors.
> 
> Not with my C compiler, as each module will then expect to import it 
> from elsewhere, but no other module will export it, so 'i' is undefined 
> at the link stage.
> 

I presume that's what he meant - an error at linking, not during 
compilation.

>> 2) If you "extern" it nowhere, it works fine.
> 
> Again, not with my C compiler. Without extern and without static, each 
> 'int i' is defined in each module then exported. You get multiple 
> definitions.
> 

Good - that's the way I like it.  I use the "-fno-common" flag in gcc to 
disable common sections.  But it will cause trouble with code written 
with the belief that multiple uninitialised definitions are okay.

> Some compilers' linkers will take care of that, provided not more than 
> one 'i' is initialised, and reduce multiple instances to 1, or with zero 
> instances, somehow magic one instance out of nowhere, and belonging to 
> no module.
> 
> That encourages sloppiness which one day will bite (like a lot of things 
> with C that I find sloppy).

Yes.  The C language does not allow such multiple definitions, but many 
compilers do - and many programmers write code that relies on this 
behaviour.  And I agree it is sloppy coding.

> 
> It also means that to the reader who needs to maintain the code, how 
> will they know which module 'owns' the variable, or which module exports 
> it?
> 
>>
>> My question is: Is the later case OK?  Is it OK to just declare it 
>> normally
>> in every module and not bother with "extern" ?
> 
> If not using shared headers but ad-hoc declarations in each module:

Why would you /not/ want shared headers?  Is that because you like 
duplicating code, or because you like having a higher risk of mistakes 
in the code?

> 
> (1) Decide which module should export the variable, and declare it as:
> 
>      int i;           // with optional initial value
> 
>      in that module;
> 
> (2) In all other modules, declare it as:
> 
>      extern int i;
> 
> 
> If using a shared header, then declare it as
> 
>     extern int i;
> 
> in that header, which is included by all the modules (that can include 
> the one exporting it). In the module exporting it, declare as:
> 
>     int i;        // optional init
> 
> If this module includes the header, it will see both 'extern int i' and 
> 'int i', but that's OK; the latter exporting declaration takes priority.
> 

Correct, except that it is not a matter of the "int i;" taking 
"priority" over the "extern int i;".  It is fine to have both, in either 
order.

IMHO it is an excellent idea for the module that defines "int i;" to 
include the shared header with "extern int i;".  That is how you ensure 
that your variable is consistent throughout the program, and you can't 
do half the job if you ever change it.  With manual "extern" 
declarations in C files, it is far too easy to end up with "int i;" and 
a mixture of "extern int i;" and "extern double i;" in different modules 
if you change the type - with the error being undetected by compilation 
and linking.  Stick to a solid rule of "extern" in shared headers and 
the definition in a single module which includes this header, and you 
can't get this wrong.

(I'm not quite sure what you mean by "shared header" - if code or 
definitions are not shared and used by more than one translation unit, 
why is it in a header rather than local to that translation unit?  /All/ 
my headers are shared, in the sense of being included by more than one 
implementation file.)

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


#145738

FromLew Pitcher <lew.pitcher@digitalfreehold.ca>
Date2019-08-20 13:54 -0400
Message-ID<qjhc5g$1f5$1@dont-email.me>
In reply to#145737
David Brown wrote:

> On 20/08/2019 17:41, Bart wrote:
>> On 20/08/2019 14:11, Kenny McCormack wrote:
>>> Suppose you have multiple source files and you want to share access to a
>>> global (see footnote) variable.  The usual method is to define it in one
>>> module and "extern" it everywhere else.  E.g.:
>>>
>>> /* In one module */
>>> int i;
>>>
>>> /* Everywhere else */
>>> extern int i;
>>>
>>> But what happens if you break this pattern?  I've determined that:
>>>
>>> 1) If you "extern" it everywhere, you get "undefined variable" errors.
>> 
>> Not with my C compiler, as each module will then expect to import it
>> from elsewhere, but no other module will export it, so 'i' is undefined
>> at the link stage.
>> 
> 
> I presume that's what he meant - an error at linking, not during
> compilation.
> 
>>> 2) If you "extern" it nowhere, it works fine.
>> 
>> Again, not with my C compiler. Without extern and without static, each
>> 'int i' is defined in each module then exported. You get multiple
>> definitions.
>> 
> 
> Good - that's the way I like it.  I use the "-fno-common" flag in gcc to
> disable common sections.  But it will cause trouble with code written
> with the belief that multiple uninitialised definitions are okay.
> 
>> Some compilers' linkers will take care of that, provided not more than
>> one 'i' is initialised, and reduce multiple instances to 1, or with zero
>> instances, somehow magic one instance out of nowhere, and belonging to
>> no module.
>> 
>> That encourages sloppiness which one day will bite (like a lot of things
>> with C that I find sloppy).
> 
> Yes.  The C language does not allow such multiple definitions,


Perhaps I'm misreading the C standard, but I believe that the C standard 
explicitly disagrees with your assertion.

In the C11 standard (the n1570 document), Section 6.2.2 (Linkages of 
Identifiers) paragraph 5 states "If the declaration of an identifier for an 
object has file scope and no storage-class specifier, its linkage is 
external." Thus, the standard requires that C treat the "global variable" 
(sic) in question as if it were declared "extern".

Additionally, in paragraph 2 of that section, the standard states "In the 
set of translation units and libraries that constitutes an entire program, 
each declaration of a particular identifier with external linkage denotes 
the same object or function." So, all identically-named "global variables" 
(sic) that appear with external linkage in other modules reference the same 
object.

If anything, the prohibition you refer to resides outside the language, in 
the definition of, and tools that support, object module linking.

> but many
> compilers do - and many programmers write code that relies on this
> behaviour.  And I agree it is sloppy coding.

For some definitions of "sloppy". YMMV


[snip]


-- 
Lew Pitcher
"In Skills, We Trust"

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


#145742

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2019-08-21 02:09 +0100
Message-ID<877e77b9zk.fsf@bsb.me.uk>
In reply to#145738
Lew Pitcher <lew.pitcher@digitalfreehold.ca> writes:

> David Brown wrote:
<cut>
>> Yes.  The C language does not allow such multiple definitions,
>
> Perhaps I'm misreading the C standard, but I believe that the C standard 
> explicitly disagrees with your assertion.
>
> In the C11 standard (the n1570 document), Section 6.2.2 (Linkages of 
> Identifiers) paragraph 5 states "If the declaration of an identifier for an 
> object has file scope and no storage-class specifier, its linkage is 
> external." Thus, the standard requires that C treat the "global variable" 
> (sic) in question as if it were declared "extern".
>
> Additionally, in paragraph 2 of that section, the standard states "In the 
> set of translation units and libraries that constitutes an entire program, 
> each declaration of a particular identifier with external linkage denotes 
> the same object or function." So, all identically-named "global variables" 
> (sic) that appear with external linkage in other modules reference the same 
> object.
>
> If anything, the prohibition you refer to resides outside the language, in 
> the definition of, and tools that support, object module linking.

6.9 p5:

  An /external definition/ is an external declaration that is also a
  definition of a function (other than an inline definition) or an
  object. If an identifier declared with external linkage is used in an
  expression (other than as part of the operand of a sizeof or _Alignof
  operator whose result is an integer constant), somewhere in the entire
  program there shall be exactly one external definition for the
  identifier; otherwise, there shall be no more than one.

-- 
Ben.

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


#145743

FromDavid Brown <david.brown@hesbynett.no>
Date2019-08-21 10:54 +0200
Message-ID<qjj0sq$t4n$1@dont-email.me>
In reply to#145738
On 20/08/2019 19:54, Lew Pitcher wrote:
> David Brown wrote:
> 
>> On 20/08/2019 17:41, Bart wrote:
>>> On 20/08/2019 14:11, Kenny McCormack wrote:
>>>> Suppose you have multiple source files and you want to share access to a
>>>> global (see footnote) variable.  The usual method is to define it in one
>>>> module and "extern" it everywhere else.  E.g.:
>>>>
>>>> /* In one module */
>>>> int i;
>>>>
>>>> /* Everywhere else */
>>>> extern int i;
>>>>
>>>> But what happens if you break this pattern?  I've determined that:
>>>>
>>>> 1) If you "extern" it everywhere, you get "undefined variable" errors.
>>>
>>> Not with my C compiler, as each module will then expect to import it
>>> from elsewhere, but no other module will export it, so 'i' is undefined
>>> at the link stage.
>>>
>>
>> I presume that's what he meant - an error at linking, not during
>> compilation.
>>
>>>> 2) If you "extern" it nowhere, it works fine.
>>>
>>> Again, not with my C compiler. Without extern and without static, each
>>> 'int i' is defined in each module then exported. You get multiple
>>> definitions.
>>>
>>
>> Good - that's the way I like it.  I use the "-fno-common" flag in gcc to
>> disable common sections.  But it will cause trouble with code written
>> with the belief that multiple uninitialised definitions are okay.
>>
>>> Some compilers' linkers will take care of that, provided not more than
>>> one 'i' is initialised, and reduce multiple instances to 1, or with zero
>>> instances, somehow magic one instance out of nowhere, and belonging to
>>> no module.
>>>
>>> That encourages sloppiness which one day will bite (like a lot of things
>>> with C that I find sloppy).
>>
>> Yes.  The C language does not allow such multiple definitions,
> 
> 
> Perhaps I'm misreading the C standard, but I believe that the C standard 
> explicitly disagrees with your assertion.
> 
> In the C11 standard (the n1570 document), Section 6.2.2 (Linkages of 
> Identifiers) paragraph 5 states "If the declaration of an identifier for an 
> object has file scope and no storage-class specifier, its linkage is 
> external." Thus, the standard requires that C treat the "global variable" 
> (sic) in question as if it were declared "extern".
> 

If you write "int i;", at file scope and with no other declarations in
force, it is a "tentative definition".  You can have as many such
tentative definitions in a translation unit as you want.  If there are
no initialising definitions (like "int i = 123;") found by the end of
the unit, it is treated as though you had written "int i = 0;".
(Compilers may handle "int i;" and "int i = 0;" differently, but
semantically in the C language there is no difference.)

You can think of "int i;" as acting like "extern int i; int i = 0;",
except that you can write it many times in one unit (you can't duplicate
initialising definitions, only tentative definitions).

(There is no C term "initialising definition" - it's just called a
"definitions" or sometimes an "external definition", but I think it
makes my point clearer.  "Tentative definition" is a real C standard term.)

So "int i;" will result in the variable being defined in that unit.
This is fine - there is no problem with that.

But if you link together a program with multiple definitions of "i",
such as you get when you have "int i;" in a shared header or explicitly
in multiple files, then it breaks the C rules.  (Ben's post has the
details.)



> Additionally, in paragraph 2 of that section, the standard states "In the 
> set of translation units and libraries that constitutes an entire program, 
> each declaration of a particular identifier with external linkage denotes 
> the same object or function." So, all identically-named "global variables" 
> (sic) that appear with external linkage in other modules reference the same 
> object.
> 
> If anything, the prohibition you refer to resides outside the language, in 
> the definition of, and tools that support, object module linking.

No.  The problem comes if you have multiple definitions "int i;" in
different files, linked in the program.  You are only allowed one
definition of any externally linked function or object (or zero
definitions, if the object or function is not actually accessed).

> 
>> but many
>> compilers do - and many programmers write code that relies on this
>> behaviour.  And I agree it is sloppy coding.
> 
> For some definitions of "sloppy". YMMV
> 

At best, it is relying on implementation-specific extensions that
combine the multiple definitions at link time.  It is a risky extension,
significantly reducing the possibility of checking for certain kinds of
errors.  It is generally poorly defined and documented.  There are
clearer, precisely defined and portable alternatives, with no cost in
efficiency or any other cost.

So putting "int i;" in headers instead of "extern int i;" is pure
laziness, with many disadvantages and no advantages.

That fits within /my/ definition of "sloppy programming".  Does it not
fit within /your/ definition?

Ignorance, poor teaching, imprecise tutorials, etc., might be an excuse
for not understanding the issue.  And certainly there is more than
enough code with such mistakes that one can be forgiven for thinking it
is allowed.  But now you know better :-)

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


#145741

FromBart <bc@freeuk.com>
Date2019-08-21 00:41 +0100
Message-ID<xy%6F.174796$4F2.146105@fx26.am4>
In reply to#145737
On 20/08/2019 18:27, David Brown wrote:
> On 20/08/2019 17:41, Bart wrote:

>> If not using shared headers but ad-hoc declarations in each module:
> 
> Why would you /not/ want shared headers?  Is that because you like 
> duplicating code, or because you like having a higher risk of mistakes 
> in the code?

Because headers weren't mentioned in the OP.

It's also possible headers are not shared (or have a more complex 
relationship with the set of .c files), or are not used at all. For 
example, generated code could create a customised set of declarations at 
the start of each module, then that's a set of header files that are not 
needed.

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


#145744

FromDavid Brown <david.brown@hesbynett.no>
Date2019-08-21 10:58 +0200
Message-ID<qjj12v$v3e$1@dont-email.me>
In reply to#145741
On 21/08/2019 01:41, Bart wrote:
> On 20/08/2019 18:27, David Brown wrote:
>> On 20/08/2019 17:41, Bart wrote:
> 
>>> If not using shared headers but ad-hoc declarations in each module:
>>
>> Why would you /not/ want shared headers?  Is that because you like
>> duplicating code, or because you like having a higher risk of mistakes
>> in the code?
> 
> Because headers weren't mentioned in the OP.

True.  But we are showing better programming practices.

> 
> It's also possible headers are not shared (or have a more complex
> relationship with the set of .c files), or are not used at all. For
> example, generated code could create a customised set of declarations at
> the start of each module, then that's a set of header files that are not
> needed.
> 

Generated code is a valid reason for not using headers - and it should
not have a risk of mistakes about declarations and definitions of
objects or functions, since that should be handled before the code is
generated.  So that is fair enough.

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


#145736

Fromrichard@cogsci.ed.ac.uk (Richard Tobin)
Date2019-08-20 16:10 +0000
Message-ID<qjh61m$k28$1@macpro.inf.ed.ac.uk>
In reply to#145732
In article <qjgric$8u2$1@news.xmission.com>,
Kenny McCormack <gazelle@shell.xmission.com> wrote:

>Suppose you have multiple source files and you want to share access to a
>global (see footnote) variable.  The usual method is to define it in one
>module and "extern" it everywhere else.  E.g.:
>
>/* In one module */
>int i;
>
>/* Everywhere else */
>extern int i;

Actually, the usual method is to define it in one file and extern it
everywhere *including* that file.  The extern declaration is
usually[*] in a .h file that is included in the .c file that defines
the variable.

[*] of course I haven't measured this.

-- Richard

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


#145740

FromSiri Cruise <chine.bleu@yahoo.com>
Date2019-08-20 16:23 -0700
Message-ID<chine.bleu-918FF8.16230920082019@reader.eternal-september.org>
In reply to#145736
In article <qjh61m$k28$1@macpro.inf.ed.ac.uk>,
 richard@cogsci.ed.ac.uk (Richard Tobin) wrote:

> In article <qjgric$8u2$1@news.xmission.com>,
> Kenny McCormack <gazelle@shell.xmission.com> wrote:
> 
> >Suppose you have multiple source files and you want to share access to a
> >global (see footnote) variable.  The usual method is to define it in one
> >module and "extern" it everywhere else.  E.g.:
> >
> >/* In one module */
> >int i;
> >
> >/* Everywhere else */
> >extern int i;
> 
> Actually, the usual method is to define it in one file and extern it
> everywhere *including* that file.  The extern declaration is
> usually[*] in a .h file that is included in the .c file that defines
> the variable.
> 
> [*] of course I haven't measured this.
> 
> -- Richard

extern is the variable equivalent of a function prototype, and non-extern to the 
function declaration.

You can also use extern within a function to make an external symbol available 
to just that one function.

-- 
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted.    @
'I desire mercy, not sacrifice.'                                    /|\
The first law of discordiamism: The more energy   This post         / \
to make order is nore energy made into entropy.   insults Islam.  Mohammed

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


#145747

Fromalready5chosen@yahoo.com
Date2019-08-21 06:50 -0700
Message-ID<53bbfbee-9a43-4980-b800-0667d8f3497a@googlegroups.com>
In reply to#145732
On Tuesday, August 20, 2019 at 4:11:54 PM UTC+3, Kenny McCormack wrote:
> Suppose you have multiple source files and you want to share access to a
> global (see footnote) variable.  The usual method is to define it in one
> module and "extern" it everywhere else.  E.g.:
> 
> /* In one module */
> int i;
> 
> /* Everywhere else */
> extern int i;
> 
> But what happens if you break this pattern?  I've determined that:
> 
> 1) If you "extern" it everywhere, you get "undefined variable" errors.
> 

That's how it should be.

> 2) If you "extern" it nowhere, it works fine.
> 

That's non-standard, but in accordance with ancient UNIX tradition.
Try to not rely on it if you care about non-UNIX.

> My question is: Is the later case OK?  Is it OK to just declare it normally
> in every module and not bother with "extern" ?
> 
> I remember reading somewhere long ago that historically this works, but
> that it isn't guaranteed.
> 
> Footnote: Uh, oh.  I said "the 'g' word"...
> 
> -- 
> "We should always be disposed to believe that which appears to us to be
> white is really black, if the hierarchy  of the church so decides." 
> 
>     - Saint Ignatius Loyola (1491-1556) Founder of the Jesuit Order -

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


#145756

Fromgazelle@shell.xmission.com (Kenny McCormack)
Date2019-08-22 20:20 +0000
Message-ID<qjmtdh$34a$1@news.xmission.com>
In reply to#145747
In article <53bbfbee-9a43-4980-b800-0667d8f3497a@googlegroups.com>,
 <already5chosen@yahoo.com> wrote:
...
>> 2) If you "extern" it nowhere, it works fine.
>
>That's non-standard, but in accordance with ancient UNIX tradition.
>Try to not rely on it if you care about non-UNIX.

I don't.

Here's what I get from the responses so far:

If you filter out all the usual Usenet noise, it boils down to "It's not
"standard", but it works on Unix".  I'm fine with that.

Now, here where it gets interesting.  I'm writing a shared library.  The
routines in the shared library need to share access to a global variable
("int i" in the above examples).  So, I do "int i" at file level and it all
works fine.  Now, the thing is, the host program (the program that loads
the library) may or may not have declared its own "int i".  If it has, I
want to use it (the host program's variable), rather than my own.  (If it
doesn't, then of course I need to use my own...)

    1) Will this "coalesce" as expected?

    2) Is there another way to get what I want?

-- 

"If God wanted us to believe in him, he'd exist."

    (Linda Smith on "10 Funniest Londoners", TimeOut, 23rd June, 2005.)

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


#145757

FromDavid Brown <david.brown@hesbynett.no>
Date2019-08-23 00:25 +0200
Message-ID<qjn4oi$7ac$1@dont-email.me>
In reply to#145756
On 22/08/2019 22:20, Kenny McCormack wrote:
> In article <53bbfbee-9a43-4980-b800-0667d8f3497a@googlegroups.com>,
>   <already5chosen@yahoo.com> wrote:
> ...
>>> 2) If you "extern" it nowhere, it works fine.
>>
>> That's non-standard, but in accordance with ancient UNIX tradition.
>> Try to not rely on it if you care about non-UNIX.
> 
> I don't.
> 
> Here's what I get from the responses so far:
> 
> If you filter out all the usual Usenet noise, it boils down to "It's not
> "standard", but it works on Unix".  I'm fine with that.

Don't forget that even in cases where "no extern" works, it can be less 
efficient than using "extern", and it is more error prone.  So you might 
not want to change existing code that works as needed, but you certainly 
won't want to use "no extern" in any new code.

> 
> Now, here where it gets interesting.  I'm writing a shared library.  The
> routines in the shared library need to share access to a global variable
> ("int i" in the above examples).  So, I do "int i" at file level and it all
> works fine.  Now, the thing is, the host program (the program that loads
> the library) may or may not have declared its own "int i".  If it has, I
> want to use it (the host program's variable), rather than my own.  (If it
> doesn't, then of course I need to use my own...)
> 
>      1) Will this "coalesce" as expected?
> 
>      2) Is there another way to get what I want?
> 

Are you talking about a dynamically loaded shared library (DLL / so) ? 
If so, I /think/ its global data is private to the library - you need to 
explicitly export data, just like exporting functions.  But I am not an 
expert in that area.

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


#145758

FromBart <bc@freeuk.com>
Date2019-08-23 01:35 +0100
Message-ID<ZxG7F.38576$qd4.34356@fx17.am4>
In reply to#145756
On 22/08/2019 21:20, Kenny McCormack wrote:
> In article <53bbfbee-9a43-4980-b800-0667d8f3497a@googlegroups.com>,
>   <already5chosen@yahoo.com> wrote:
> ...
>>> 2) If you "extern" it nowhere, it works fine.
>>
>> That's non-standard, but in accordance with ancient UNIX tradition.
>> Try to not rely on it if you care about non-UNIX.
> 
> I don't.
> 
> Here's what I get from the responses so far:
> 
> If you filter out all the usual Usenet noise, it boils down to "It's not
> "standard", but it works on Unix".  I'm fine with that.

I guess by 'Unix', people mean 'gcc'.

> Now, here where it gets interesting.  I'm writing a shared library.  The
> routines in the shared library need to share access to a global variable
> ("int i" in the above examples).  So, I do "int i" at file level and it all
> works fine.  Now, the thing is, the host program (the program that loads
> the library) may or may not have declared its own "int i".  If it has, I
> want to use it (the host program's variable), rather than my own.  (If it
> doesn't, then of course I need to use my own...)
> 
>      1) Will this "coalesce" as expected?

If you mean, given one of multiple invocations of the library (since it 
is 'shared'), whether that can somehow interrogate the program that 
invoked that version, and find out whether it exported that variable and 
what its address is, then I don't think that's possible.

The shared library needs to be built before the host program runs (maybe 
before it's even written), and any reference to 'i' must be satisfied 
then, if it accesses it directly.


>      2) Is there another way to get what I want?

Add an initialisation function to the library that the host program must 
call. That either passes the address of the host's 'i' variable, if 
available, or passes NULL (or does not call the function) when it is not 
provided.

The library needs to access 'i' via a pointer, which is either set to 
point to its own 'i', or to the host's 'i' via that function.

Example, in library:

   int i;

   int I = &i;  // (if I is shared, then only this is initialised)

   void library_init(int *ia) {
        if (ia) I = ia;
   }

   // 'i' is accessed as *I ....

In host, optional code:

   int i;                  // (doesn't need to be the same name)
   library_init(&i);

If you want to use 'i' in the library code rather than '*I', then that's 
trickier. (Possibly, use a macro that maps 'i' to *I, reversing the 
roles of i and I above.)




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


#145760

Fromgazelle@shell.xmission.com (Kenny McCormack)
Date2019-08-23 03:40 +0000
Message-ID<qjnn6u$qpk$1@news.xmission.com>
In reply to#145758
In article <ZxG7F.38576$qd4.34356@fx17.am4>, Bart  <bc@freeuk.com> wrote:
>On 22/08/2019 21:20, Kenny McCormack wrote:
>> In article <53bbfbee-9a43-4980-b800-0667d8f3497a@googlegroups.com>,
>>   <already5chosen@yahoo.com> wrote:
>> ...
>>>> 2) If you "extern" it nowhere, it works fine.
>>>
>>> That's non-standard, but in accordance with ancient UNIX tradition.
>>> Try to not rely on it if you care about non-UNIX.
>> 
>> I don't.
>> 
>> Here's what I get from the responses so far:
>> 
>> If you filter out all the usual Usenet noise, it boils down to "It's not
>> "standard", but it works on Unix".  I'm fine with that.
>
>I guess by 'Unix', people mean 'gcc'.

I don't know about "people", but, yes, for my purposes, the world is gcc
and Linux.

>> Now, here where it gets interesting.  I'm writing a shared library.  The
>> routines in the shared library need to share access to a global variable
>> ("int i" in the above examples).  So, I do "int i" at file level and it all
>> works fine.  Now, the thing is, the host program (the program that loads
>> the library) may or may not have declared its own "int i".  If it has, I
>> want to use it (the host program's variable), rather than my own.  (If it
>> doesn't, then of course I need to use my own...)
>> 
>>      1) Will this "coalesce" as expected?
>
>If you mean, given one of multiple invocations of the library (since it 
>is 'shared'), whether that can somehow interrogate the program that 
>invoked that version, and find out whether it exported that variable and 
>what its address is, then I don't think that's possible.

First of all, I've analyzed this problem pretty thoroughly (I think), and
concluded that it is almost, but not quite doable.  See below.  The "almost
- really, almost - is p*ssing me off...".

You can determine whether a symbol exists in the main program using
dlsym(). dlsym(someHandle,"someSymbol") will return NULL if the symbol
isn't found, or its address if it is.  I'm pretty sure, though haven't
tested directly yet, that you would then use dladdr() to figure out which
file (i.e, either the main() program or the shared lib) contains that symbol.

>The shared library needs to be built before the host program runs (maybe 
>before it's even written), and any reference to 'i' must be satisfied 
>then, if it accesses it directly.
>
>
>>      2) Is there another way to get what I want?
>
>Add an initialisation function to the library that the host program must 
>call. That either passes the address of the host's 'i' variable, if 
>available, or passes NULL (or does not call the function) when it is not 
>provided.

That works *PROVIDED* you can always modify the host program.  That's easy
enough.  The rub is that I want it to work both on modified and unmodified
hosts.  I.e., I want my library to be loadable and usable by off-the-shelf
versions of <host program>.

That's the rub...

BTW, the following test program demonstrates, at least to my satisfaction,
that the hoped-for coalescing does not happen (Fooey!):

Compile as shown; compile the main program with and without -DDEFINE_I.

--- Cut Here ---
#include <stdio.h>

#ifdef SHARED
/* Compile: gcc -DSHARED -fPIC -s -shared -W -Wall -Werror -o TestCoalesce.so TestCoalesce.c */
int i;
void TestIt(void) { printf("Value of i in TestIt(): %d\n",i); }
#else
/* Compile: gcc [-DDEFINE_I] -s -W -Wall -Werror -o TestCoalesce TestCoalesce.c -ldl */
#ifdef DEFINE_I
int i;
#endif
#include <dlfcn.h>
#include <assert.h>
int main(void)
{
    void *handle;
    void (*the_fun)();

#ifdef DEFINE_I
    i = 7;
    printf("Value of i in main(): %d\n",i);
#endif
    assert((handle = dlopen("./TestCoalesce.so",RTLD_NOW)));
    assert((the_fun = dlsym(handle,"TestIt")));
    the_fun();
}
#endif
--- Cut Here ---

-- 
"We should always be disposed to believe that which appears to us to be
white is really black, if the hierarchy  of the church so decides." 

    - Saint Ignatius Loyola (1491-1556) Founder of the Jesuit Order -

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


#145762

FromBart <bc@freeuk.com>
Date2019-08-23 11:09 +0100
Message-ID<eXO7F.39327$VT3.197@fx19.am4>
In reply to#145760
On 23/08/2019 04:40, Kenny McCormack wrote:
> In article <ZxG7F.38576$qd4.34356@fx17.am4>, Bart  <bc@freeuk.com> wrote:

>> If you mean, given one of multiple invocations of the library (since it
>> is 'shared'), whether that can somehow interrogate the program that
>> invoked that version, and find out whether it exported that variable and
>> what its address is, then I don't think that's possible.
> 
> First of all, I've analyzed this problem pretty thoroughly (I think), and
> concluded that it is almost, but not quite doable.  See below.  The "almost
> - really, almost - is p*ssing me off...".
> 
> You can determine whether a symbol exists in the main program using
> dlsym().

You call dlsym() by passing it a handle to the library, obtained with 
dlopen(). Here you want to do a reverse look-up: a library calling 
dlopen() on its invoking program. And the first problem is obtaining the 
name of that program.

I'm assuming ordinary executables can export their globals in a way that 
can be picked up by another program using dlopen/dlsym.

But my tests trying that under Windows, using the equivalent 
LoadLibrary/GetProcAddress, didn't seem to work.

  dlsym(someHandle,"someSymbol") will return NULL if the symbol
> isn't found, or its address if it is.  I'm pretty sure, though haven't
> tested directly yet, that you would then use dladdr() to figure out which
> file (i.e, either the main() program or the shared lib) contains that symbol.

I'm not familiar with dladdr.

>      assert((handle = dlopen("./TestCoalesce.so",RTLD_NOW)));

Shouldn't it be a routine inside TestCoalesce.so opening the program 
that's using TestCoalesce.so?

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


#145761

FromDavid Brown <david.brown@hesbynett.no>
Date2019-08-23 08:16 +0200
Message-ID<qjo0cg$rqk$1@dont-email.me>
In reply to#145758
On 23/08/2019 02:35, Bart wrote:
> On 22/08/2019 21:20, Kenny McCormack wrote:
>> In article <53bbfbee-9a43-4980-b800-0667d8f3497a@googlegroups.com>,
>>   <already5chosen@yahoo.com> wrote:
>> ...
>>>> 2) If you "extern" it nowhere, it works fine.
>>>
>>> That's non-standard, but in accordance with ancient UNIX tradition.
>>> Try to not rely on it if you care about non-UNIX.
>>
>> I don't.
>>
>> Here's what I get from the responses so far:
>>
>> If you filter out all the usual Usenet noise, it boils down to "It's not
>> "standard", but it works on Unix".  I'm fine with that.
> 
> I guess by 'Unix', people mean 'gcc'.

Unless he says different, I'll assume he means "*nix" when he writes 
"Unix" (since systems like Linux are Unix-like, but not Unix). 
Generally when people mean "gcc", they write "gcc".

Using "int i;" everywhere (with no initialised definitions) works with 
most compilers, on most systems.  The /reason/ for it being supported 
may come from the depths of Unix history, but it not restricted to Unix, 
or *nix, systems, nor to compilers that come from there.  In fact, your 
is the only compiler I have ever heard of that does not support it by 
default - other compilers need flags to disable the "feature", if it can 
be disabled at all.  (Again, I think it is good that you don't support 
this misfeature, though it might limit the code you can compile.)

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


#145763

Fromscott@slp53.sl.home (Scott Lurndal)
Date2019-08-23 15:02 +0000
Message-ID<oeT7F.52340$GI3.27684@fx03.iad>
In reply to#145756
gazelle@shell.xmission.com (Kenny McCormack) writes:
>In article <53bbfbee-9a43-4980-b800-0667d8f3497a@googlegroups.com>,
> <already5chosen@yahoo.com> wrote:
>...
>>> 2) If you "extern" it nowhere, it works fine.
>>
>>That's non-standard, but in accordance with ancient UNIX tradition.
>>Try to not rely on it if you care about non-UNIX.
>
>I don't.
>
>Here's what I get from the responses so far:
>
>If you filter out all the usual Usenet noise, it boils down to "It's not
>"standard", but it works on Unix".  I'm fine with that.
>
>Now, here where it gets interesting.  I'm writing a shared library.  The
>routines in the shared library need to share access to a global variable
>("int i" in the above examples).  So, I do "int i" at file level and it all
>works fine.  Now, the thing is, the host program (the program that loads
>the library) may or may not have declared its own "int i".  If it has, I
>want to use it (the host program's variable), rather than my own.  (If it
>doesn't, then of course I need to use my own...)
>

Declare the 'i' in the library as 'weak'.

int i __attribute__((weak));

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


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

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


csiph-web