Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #145732 > unrolled thread
| Started by | gazelle@shell.xmission.com (Kenny McCormack) |
|---|---|
| First post | 2019-08-20 13:11 +0000 |
| Last post | 2019-09-06 20:24 +0200 |
| Articles | 20 on this page of 42 — 15 participants |
Back to article view | Back to comp.lang.c
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 →
| From | gazelle@shell.xmission.com (Kenny McCormack) |
|---|---|
| Date | 2019-08-20 13:11 +0000 |
| Subject | Question 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]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2019-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]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-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]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-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]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2019-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]
| From | Lew Pitcher <lew.pitcher@digitalfreehold.ca> |
|---|---|
| Date | 2019-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2019-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]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2019-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]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-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]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2019-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]
| From | richard@cogsci.ed.ac.uk (Richard Tobin) |
|---|---|
| Date | 2019-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]
| From | Siri Cruise <chine.bleu@yahoo.com> |
|---|---|
| Date | 2019-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]
| From | already5chosen@yahoo.com |
|---|---|
| Date | 2019-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]
| From | gazelle@shell.xmission.com (Kenny McCormack) |
|---|---|
| Date | 2019-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]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2019-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]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-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]
| From | gazelle@shell.xmission.com (Kenny McCormack) |
|---|---|
| Date | 2019-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]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-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]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2019-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]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2019-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