Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #103611 > unrolled thread
| Started by | BartC <bc@freeuk.com> |
|---|---|
| First post | 2017-02-10 17:16 +0000 |
| Last post | 2017-02-11 03:17 -0800 |
| Articles | 20 on this page of 105 — 19 participants |
Back to article view | Back to comp.lang.c
Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-10 17:16 +0000
Re: Is 'extern' necessary? Keith Thompson <kst-u@mib.org> - 2017-02-10 09:33 -0800
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-10 18:41 +0000
Re: Is 'extern' necessary? Keith Thompson <kst-u@mib.org> - 2017-02-10 12:09 -0800
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-10 20:29 +0000
Re: Is 'extern' necessary? Keith Thompson <kst-u@mib.org> - 2017-02-10 13:26 -0800
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-10 22:56 +0000
Re: Is 'extern' necessary? jameskuyper@verizon.net - 2017-02-10 20:19 -0800
Re: Is 'extern' necessary? "James R. Kuyper" <jameskuyper@verizon.net> - 2017-02-11 09:53 -0500
Re: Is 'extern' necessary? Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-13 05:19 -0800
Re: Is 'extern' necessary? jameskuyper@verizon.net - 2017-02-10 12:09 -0800
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-10 20:50 +0000
Re: Is 'extern' necessary? supercat@casperkitty.com - 2017-02-10 13:09 -0800
Re: Is 'extern' necessary? Keith Thompson <kst-u@mib.org> - 2017-02-10 13:33 -0800
Re: Is 'extern' necessary? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-02-10 23:23 +0000
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-10 23:35 +0000
Re: Is 'extern' necessary? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-02-11 00:34 +0000
Re: Is 'extern' necessary? David Brown <david.brown@hesbynett.no> - 2017-02-13 12:41 +0100
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-13 13:14 +0000
Re: Is 'extern' necessary? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-02-13 14:05 +0000
Re: Is 'extern' necessary? jameskuyper@verizon.net - 2017-02-13 07:49 -0800
Re: Is 'extern' necessary? jameskuyper@verizon.net - 2017-02-10 19:33 -0800
Re: Is 'extern' necessary? supercat@casperkitty.com - 2017-02-11 09:41 -0800
Re: Is 'extern' necessary? Keith Thompson <kst-u@mib.org> - 2017-02-11 10:19 -0800
Re: Is 'extern' necessary? "James R. Kuyper" <jameskuyper@verizon.net> - 2017-02-11 13:39 -0500
Re: Is 'extern' necessary? supercat@casperkitty.com - 2017-02-12 10:10 -0800
Re: Is 'extern' necessary? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2017-02-10 14:59 -0800
Re: Is 'extern' necessary? David Brown <david.brown@hesbynett.no> - 2017-02-13 12:33 +0100
Re: Is 'extern' necessary? Siri Cruise <chine.bleu@yahoo.com> - 2017-02-10 09:35 -0800
Re: Is 'extern' necessary? Keith Thompson <kst-u@mib.org> - 2017-02-10 12:12 -0800
Re: Is 'extern' necessary? jameskuyper@verizon.net - 2017-02-10 10:38 -0800
Re: Is 'extern' necessary? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-02-10 21:10 +0000
Re: Is 'extern' necessary? supercat@casperkitty.com - 2017-02-10 13:25 -0800
Re: Is 'extern' necessary? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2017-02-10 14:53 -0800
Re: Is 'extern' necessary? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2017-02-10 15:06 -0800
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-10 23:24 +0000
Re: Is 'extern' necessary? Ian Collins <ian-news@hotmail.com> - 2017-02-11 12:34 +1300
Re: Is 'extern' necessary? David Brown <david.brown@hesbynett.no> - 2017-02-13 13:14 +0100
Re: Is 'extern' necessary? GOTHIER Nathan <nathan.gothier@gmail.com> - 2017-02-13 13:44 +0100
Re: Is 'extern' necessary? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-02-13 14:13 +0000
Re: Is 'extern' necessary? David Brown <david.brown@hesbynett.no> - 2017-02-13 15:16 +0100
Re: Is 'extern' necessary? GOTHIER Nathan <nathan.gothier@gmail.com> - 2017-02-13 17:24 +0100
Re: Is 'extern' necessary? "James R. Kuyper" <jameskuyper@verizon.net> - 2017-02-13 14:24 -0500
Re: Is 'extern' necessary? David Brown <david.brown@hesbynett.no> - 2017-02-13 23:29 +0100
Re: Is 'extern' necessary? Keith Thompson <kst-u@mib.org> - 2017-02-13 11:06 -0800
Re: Is 'extern' necessary? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2017-02-13 11:15 -0800
Re: Is 'extern' necessary? "James R. Kuyper" <jameskuyper@verizon.net> - 2017-02-13 11:48 -0500
Re: Is 'extern' necessary? supercat@casperkitty.com - 2017-02-13 09:03 -0800
Re: Is 'extern' necessary? David Brown <david.brown@hesbynett.no> - 2017-02-13 23:37 +0100
Re: Is 'extern' necessary? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2017-02-10 15:40 -0800
Re: Is 'extern' necessary? Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-13 05:09 -0800
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-13 13:46 +0000
Re: Is 'extern' necessary? Keith Thompson <kst-u@mib.org> - 2017-02-13 09:52 -0800
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-13 19:19 +0000
Re: Is 'extern' necessary? Keith Thompson <kst-u@mib.org> - 2017-02-13 11:34 -0800
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-13 20:13 +0000
Re: Is 'extern' necessary? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2017-02-13 13:11 -0800
Re: Is 'extern' necessary? David Brown <david.brown@hesbynett.no> - 2017-02-14 00:33 +0100
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-14 01:02 +0000
Re: Is 'extern' necessary? David Brown <david.brown@hesbynett.no> - 2017-02-14 09:28 +0100
Re: Is 'extern' necessary? Robert Wessel <robertwessel2@yahoo.com> - 2017-02-14 03:31 -0600
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-14 11:42 +0000
Re: Is 'extern' necessary? David Brown <david.brown@hesbynett.no> - 2017-02-14 13:29 +0100
Re: Is 'extern' necessary? supercat@casperkitty.com - 2017-02-14 05:16 -0800
Re: Is 'extern' necessary? David Brown <david.brown@hesbynett.no> - 2017-02-14 14:51 +0100
Re: Is 'extern' necessary? supercat@casperkitty.com - 2017-02-14 07:24 -0800
Re: Is 'extern' necessary? David Brown <david.brown@hesbynett.no> - 2017-02-14 21:35 +0100
Re: Is 'extern' necessary? James Kuyper <jameskuyper@verizon.net> - 2017-02-14 15:53 -0500
Re: Is 'extern' necessary? David Brown <david.brown@hesbynett.no> - 2017-02-15 09:31 +0100
Re: Is 'extern' necessary? "James R. Kuyper" <jameskuyper@verizon.net> - 2017-02-15 11:36 -0500
Re: Is 'extern' necessary? Keith Thompson <kst-u@mib.org> - 2017-02-15 09:12 -0800
Re: Is 'extern' necessary? "James R. Kuyper" <jameskuyper@verizon.net> - 2017-02-15 12:58 -0500
Re: Is 'extern' necessary? supercat@casperkitty.com - 2017-02-15 10:01 -0800
Re: Is 'extern' necessary? jameskuyper@verizon.net - 2017-02-15 10:55 -0800
Re: Is 'extern' necessary? supercat@casperkitty.com - 2017-02-15 11:42 -0800
Re: Is 'extern' necessary? jameskuyper@verizon.net - 2017-02-15 12:28 -0800
Re: Is 'extern' necessary? supercat@casperkitty.com - 2017-02-15 13:58 -0800
Re: Is 'extern' necessary? Keith Thompson <kst-u@mib.org> - 2017-02-14 08:54 -0800
Re: Is 'extern' necessary? Keith Thompson <kst-u@mib.org> - 2017-02-14 08:51 -0800
Re: Is 'extern' necessary? Richard Heathfield <rjh@cpax.org.uk> - 2017-02-14 17:32 +0000
Re: Is 'extern' necessary? Gareth Owen <gwowen@gmail.com> - 2017-02-14 17:45 +0000
Re: Is 'extern' necessary? David Brown <david.brown@hesbynett.no> - 2017-02-14 21:38 +0100
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-14 23:26 +0000
Re: Is 'extern' necessary? Keith Thompson <kst-u@mib.org> - 2017-02-14 16:33 -0800
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-15 00:47 +0000
Re: Is 'extern' necessary? Jean-Marc Bourguet <jm@bourguet.org> - 2017-02-14 18:17 +0100
Re: Is 'extern' necessary? Keith Thompson <kst-u@mib.org> - 2017-02-14 09:47 -0800
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-14 18:36 +0000
Re: Is 'extern' necessary? jameskuyper@verizon.net - 2017-02-14 11:20 -0800
Re: Is 'extern' necessary? supercat@casperkitty.com - 2017-02-14 11:42 -0800
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-14 20:22 +0000
Re: Is 'extern' necessary? Robert Wessel <robertwessel2@yahoo.com> - 2017-02-14 17:58 -0600
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-15 01:29 +0000
Re: Is 'extern' necessary? Robert Wessel <robertwessel2@yahoo.com> - 2017-02-16 05:02 -0600
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-16 11:38 +0000
Re: Is 'extern' necessary? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-02-16 14:37 +0000
Re: Is 'extern' necessary? BartC <bc@freeuk.com> - 2017-02-16 15:43 +0000
Re: Is 'extern' necessary? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-02-16 16:08 +0000
Re: Is 'extern' necessary? GOTHIER Nathan <nathan.gothier@gmail.com> - 2017-02-16 18:42 +0100
Re: Is 'extern' necessary? David Brown <david.brown@hesbynett.no> - 2017-02-15 09:47 +0100
Re: Is 'extern' necessary? Robert Wessel <robertwessel2@yahoo.com> - 2017-02-16 05:05 -0600
Re: Is 'extern' necessary? Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-15 16:53 -0800
Re: Is 'extern' necessary? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-02-10 23:55 +0000
Re: Is 'extern' necessary? Les Cargill <lcargill99@comcast.com> - 2017-02-10 19:24 -0600
Re: Is 'extern' necessary? void <nathan.gothier@gmail.com> - 2017-02-11 03:17 -0800
Page 2 of 6 — ← Prev page 1 [2] 3 4 5 6 Next page →
| From | jameskuyper@verizon.net |
|---|---|
| Date | 2017-02-13 07:49 -0800 |
| Message-ID | <cfcb370d-8ab0-45b8-b5ef-81566e53630a@googlegroups.com> |
| In reply to | #103794 |
On Monday, February 13, 2017 at 8:14:39 AM UTC-5, Bart wrote: ... > Is a linker even an official part of the language? It does seem to be a > necessary component of most implementations. A linker is not part of the language at all. It is part of most implementations of the language. The language allows you to create a program containing multiple translation units that must be linked together during translation phase 8, and it specifies how the resulting program will work in terms of how those translation units interact with each other. The standard leaves the details of how this is implemented entirely up to the implementation. It concerns itself solely with the connection between the contents of the C source code files and the behavior of the translated program - it doesn't care how that connection is achieved. If an implementation can generate the required behavior without using an separate linker program, that's fine. If it can generate that behavior without having any sub-component that could be called a "linker", that's fine, too. But most real world implementation do use a linker to implement that part of the C standard's requirements; and the ones that don't generally have one or more subroutines that could reasonably be described as "the linker".
[toc] | [prev] | [next] | [standalone]
| From | jameskuyper@verizon.net |
|---|---|
| Date | 2017-02-10 19:33 -0800 |
| Message-ID | <37272c08-9e01-4fb8-bcc5-6e63e0e723d6@googlegroups.com> |
| In reply to | #103624 |
On Friday, February 10, 2017 at 3:50:11 PM UTC-5, Bart wrote: > On 10/02/2017 20:09, jameskuyper@verizon.net wrote: ... > > In 6.9, "external" means "outside of any function" (6.9p4), whereas in most > > other parts of the standard it refers to "external linkage". > > I remember that from a previous discussion. It comes up in K&R2 1.10 > (p31): "An external variable... must be defined outside of any function. > ...The variable must also be declared in each function that wants to > access it...". And it goes on to suggest using an explicit 'extern' > statement. > > I think that's just ramped up the confusion by a magnitude or so! Your previous level of confusion about the C standard was already so high, that I find it hard to believe that it could be increased by an order of magnitude without destroying your sanity. It's just a piece of jargon, no worse than most. The standard is actually quite consistent about it. Outside of section 6.9, it almost never uses "external" in any context where both meanings are possible, and in section 6.9 it explains the different meaning that "external" has in that section (I say "almost" only because there are so many uses of the term that I can't be sure I correctly checked they all). ... > > It makes things easier for the developer, however. Each of those rules > > enables idioms that C programmers other than you find convenient. > > What sort of idioms? Putting what you would call the importing declaration of the object in a header file, so you can be certain it's exactly the same in every TU that #includes the header file, and also #including it in the same TU where what you would call the the exporting definition of that same identifier. Because of the rules you find so confusing, it's permissible for the importing declaration and the exporting definition to reside in the same TU, but a diagnostic is mandatory if they aren't compatible. Triggering that diagnostic if a mistake has been made is the reason for putting them together in the same TU. > I can see a couple of ways to share exported data in C. If module A > wants to share a named object with B: > > A.c: B.c: > > extern int abc; extern int abc; #include A.h > .... > int abc = 100; > > But it also seems to work without extern: > > A.c: B.c: > > int abc; int abc; #include A.h Never try to guess whether something is correct, based upon whether it works. This code has undefined behavior, for the reasons I've already given. That means that the C standard imposes no requirements on such code. In particular, it doesn't impose a requirement that it fail in any noticeable way. One of the most common things that happens when the behavior is undefined, is that the code works exactly the way that the author incorrectly thought it was required to work. There's a reason why these incorrect expectations exist, and that's because they match the way that many real implementations actually work. The mistake comes from incorrectly concluding that because it works that way for those implementations, it's required to work that way on all others. Only by comparing your code with the requirements of the standard can you determine whether it contains any of features that could make the behavior undefined - no amount of testing will resolve that issue. > .... > int abc = 100; > > Here, B doesn't know if abc belongs to B, or is imported from elsewhere. > A can assume that abc does belong because it's initialised. So object > files for both A and B appear to export abc, so only one is chosen by > the linker (since A contains init data for abc, that can be chosen). > > The same thing applies when abc is a function. and the abc = 100 is > replaced a function body, except that now B /knows/ that abc has to > exist elsewhere. There is a link error if both A and B export abc with > init data or a function body. > > So, why is any other idiom needed? The usage pattern required is simple. To cope with linkers that don't behave the way you incorrectly believe they're required to behave - which is true of many real-world linkers. I've even heard of linkers which, when given two definitions of the same identifier with external linkage in two different object files, will simply reserve the amount of space required by the first definition, and use that amount of space for both definitions, without even bothering to check whether the second definition requires the same amount of space, much less whether they have compatible types - the linker doesn't know anything about C's rules for compatible types. In fact, it doesn't know anything about C's types, period.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2017-02-11 09:41 -0800 |
| Message-ID | <f2c8f710-bdc3-4319-b018-757f54540b92@googlegroups.com> |
| In reply to | #103654 |
On Friday, February 10, 2017 at 9:33:12 PM UTC-6, james...@verizon.net wrote: > One of the most > common things that happens when the behavior is undefined, is that the code > works exactly the way that the author incorrectly thought it was required to > work. An even more common thing that happens when code executes behavior which is not defined by the Standard is that it will work in a predictable fashion which is defined by the target implementation, even if behavior would be unpredictable on other implementations. One of the biggest problems with C is that there hasn't been any effort to formally characterize classes of implementations which support useful guarantees beyond those required by the Standard. This is made worse by the fact that implementations seldom tried to document all of the guarantees that would seemingly-obviously follow from other documented aspects of system operation. If a build system specified that invoking the the linker with certain options would cause it to treat multiple like- named variables as a single variable, that would suggest a certain natural behavior for code containing such symbols. While it would be possible for a build system to merges symbols ad document that it does so and yet still launch nasal demons when running code that contains matching symbols, I would not consider it unreasonable for programmers to treat the documentation of the symbol matching process as a definition of behavior if the system documentation doesn't specify otherwise.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2017-02-11 10:19 -0800 |
| Message-ID | <ln7f4wvbdn.fsf@kst-u.example.com> |
| In reply to | #103687 |
supercat@casperkitty.com writes:
> On Friday, February 10, 2017 at 9:33:12 PM UTC-6, james...@verizon.net wrote:
>> One of the most
>> common things that happens when the behavior is undefined, is that the code
>> works exactly the way that the author incorrectly thought it was required to
>> work.
>
> An even more common thing that happens when code executes behavior which is
> not defined by the Standard is that it will work in a predictable fashion
> which is defined by the target implementation, even if behavior would be
> unpredictable on other implementations.
That's a subset of what James described (assuming that by "required" he
meant "required by the C standard", which I'm fairly sure he did).
> One of the biggest problems with C is that there hasn't been any effort to
> formally characterize classes of implementations which support useful
> guarantees beyond those required by the Standard.
POSIX is one such effort.
[...]
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | "James R. Kuyper" <jameskuyper@verizon.net> |
|---|---|
| Date | 2017-02-11 13:39 -0500 |
| Message-ID | <a1f35916-c895-9e9f-206d-22ddd5d75da9@verizon.net> |
| In reply to | #103689 |
On 02/11/2017 01:19 PM, Keith Thompson wrote: > supercat@casperkitty.com writes: >> On Friday, February 10, 2017 at 9:33:12 PM UTC-6, james...@verizon.net wrote: >>> One of the most >>> common things that happens when the behavior is undefined, is that the code >>> works exactly the way that the author incorrectly thought it was required to >>> work. >> >> An even more common thing that happens when code executes behavior which is >> not defined by the Standard is that it will work in a predictable fashion >> which is defined by the target implementation, even if behavior would be >> unpredictable on other implementations. > > That's a subset of what James described (assuming that by "required" he > meant "required by the C standard", which I'm fairly sure he did). That's correct.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2017-02-12 10:10 -0800 |
| Message-ID | <607e3e66-c7e5-47d3-a376-20692419854e@googlegroups.com> |
| In reply to | #103689 |
On Saturday, February 11, 2017 at 12:18:45 PM UTC-6, Keith Thompson wrote:
> supercat writes:
> > On Friday, February 10, 2017 at 9:33:12 PM UTC-6, James R. Kuyper wrote:
> >> One of the most
> >> common things that happens when the behavior is undefined, is that the code
> >> works exactly the way that the author incorrectly thought it was required to
> >> work.
> >
> > An even more common thing that happens when code executes behavior which is
> > not defined by the Standard is that it will work in a predictable fashion
> > which is defined by the target implementation, even if behavior would be
> > unpredictable on other implementations.
>
> That's a subset of what James described (assuming that by "required" he
> meant "required by the C standard", which I'm fairly sure he did).
It's not a subset, since the situation I'm describing does not rely upon the
programmers having an "incorrect" belief about anything. If code tests for
overlapping objects using something like:
int overlaps(void *base1, void *base2, size_t size)
{
void *end1 = (char*)base1 + size;
void *end2 = (char*)base2 + size;
return end1 > base2 && end2 > base1;
}
rather than:
int overlaps(void *base1, void *base2, size_t size)
{
while(--size)
{
if ((char*)base1+size == (char*)base2) return 1;
if ((char*)base2+size == (char*)base1) return 1;
}
return 0;
}
does that mean that the programmer incorrectly thought the Standard required
that implementations process the former construct usefully, or that the
programmer thought that the advantages of the former construct on platforms
where it would work were sufficient to justify limiting the program to such
platforms?
> > One of the biggest problems with C is that there hasn't been any effort to
> > formally characterize classes of implementations which support useful
> > guarantees beyond those required by the Standard.
>
> POSIX is one such effort.
For hosted implementations POSIX may be useful, but it's far less so for
embedded applications which may not support all of the features that POSIX
would mandate. Different kinds of applications benefit from different kinds
of features, so having finer granularity (e.g. being able to usefully say
that if implementation I supports features X and Y, but not Z, and program P
needs X and/or Y but not Z, then P should be able to run on I).
Some people seem to claim such granularity would cause Balkanization, but I
would suggest it would do the opposite. If code could specify that it needs
a relatively weak guarantee regarding some behavior, such code could be
accommodated efficiently by more implementations than would be possible if
the only way code could specify that it needed any guarantee was for it to
also specify a lot of things that it didn't need.
[toc] | [prev] | [next] | [standalone]
| From | Andrey Tarasevich <andreytarasevich@hotmail.com> |
|---|---|
| Date | 2017-02-10 14:59 -0800 |
| Message-ID | <o7lggb$e2f$1@dont-email.me> |
| In reply to | #103617 |
On 2/10/2017 10:41 AM, BartC wrote: > > It mentions 'external definition'. What does that mean? > > Presumably it can't mean a definition with 'extern', because if I write: No. The term is clearly defined in the standard document. "External definition" is a definition that is made "outside of any function", i.e. at file scope. E.g. 'static int i = 5;' at file scope is also an external definition. > extern int abc = 100; > > then gcc complains (but splitting it into extern int abc; int abc=100; > is OK). It issues a warning. It is just another of poorly thought through GCC warnings, created under the pressure of the masses who do not know how to use 'extern' properly. > But with this extern, tentative, storage and linkage business, it's > doing a good job of making it as fiendishly convoluted as possible. Just forget about tentative definitions, at least in the context of this question. The "tentative definition" mechanism works entirely inside a translation unit. Officially, it has no effects that cross the boundary of a translation unit. -- Best regards, Andrey Tarasevich
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2017-02-13 12:33 +0100 |
| Message-ID | <o7s5fd$jui$1@dont-email.me> |
| In reply to | #103617 |
On 10/02/17 19:41, BartC wrote: > On 10/02/2017 17:33, Keith Thompson wrote: >> BartC <bc@freeuk.com> writes: >>> I've been trying to find out what the point of 'extern' is. >> >> N1570 6.9.2, tentative definitions. > > It mentions 'external definition'. What does that mean? > > Presumably it can't mean a definition with 'extern', because if I write: > > extern int abc = 100; > > then gcc complains (but splitting it into extern int abc; int abc=100; > is OK). > > In my mind, file-scope objects can be declared in a module as either > Local, Exported or Imported. Only the first two can be initialised in > the module (initialising of an Imported object is up to the module that > exports it). In assembly, that is the common case - file-scope symbols are either local, exported, or imported. But in C, the concept is "linkage". "extern" means that a symbol has external linkage. You might be declaring it as external linkage to export it, /or/ to import it. So "extern" does /not/ mean "this identifier is defined externally". The way to import a symbol is to have only an "extern" declaration. Having a definition (without "static") is sufficient to export a symbol - but you can happily also have an "extern" declaration there. Most people make use of that when the put their "extern" declarations in a header file, and #include it in the source file that defines the object as well as ones that use it. > > I understand that in C, separate declarations that may appear > conflicting are necessary, in order to have a shared declaration of X > that can appear, via a shared header, in both modules A and B, where > there is also a second, perhaps initialised definition of X in one of > those modules. > > But with this extern, tentative, storage and linkage business, it's > doing a good job of making it as fiendishly convoluted as possible. > Having issues hidden by a compiler, or multiple definitions taken care > of by a linker, doesn't help in trying to understand. >
[toc] | [prev] | [next] | [standalone]
| From | Siri Cruise <chine.bleu@yahoo.com> |
|---|---|
| Date | 2017-02-10 09:35 -0800 |
| Message-ID | <chine.bleu-6AB450.09350710022017@news.eternal-september.org> |
| In reply to | #103611 |
In article <o7ksei$n0$1@dont-email.me>, BartC <bc@freeuk.com> wrote:
> It seems that most of the time you can get by without 'extern'. So when
> is it necessary?
aleph.c:
int beth = 0;
gimel.c:
char *beth = "%4.2d";
int daleth (void) {
extern int beth; return ++beth;
}
char *he (void) {
static char vav[100]; sprintf(vav, beth, daleth());
return vav;
}
zayin.h:
extern int beth;
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted.
'I desire mercy, not sacrifice.'
Free the Amos Yee one.
Yeah, too bad about your so-called life. Ha-ha.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2017-02-10 12:12 -0800 |
| Message-ID | <ln1sv5x0t4.fsf@kst-u.example.com> |
| In reply to | #103614 |
Siri Cruise <chine.bleu@yahoo.com> writes:
> In article <o7ksei$n0$1@dont-email.me>, BartC <bc@freeuk.com> wrote:
>
>> It seems that most of the time you can get by without 'extern'. So when
>> is it necessary?
>
> aleph.c:
> int beth = 0;
>
> gimel.c:
> char *beth = "%4.2d";
>
> int daleth (void) {
> extern int beth; return ++beth;
> }
>
> char *he (void) {
> static char vav[100]; sprintf(vav, beth, daleth());
> return vav;
> }
>
> zayin.h:
> extern int beth;
gimel.c has conflicting definitions for `beth`. An example that's legal
C would be more compelling.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | jameskuyper@verizon.net |
|---|---|
| Date | 2017-02-10 10:38 -0800 |
| Message-ID | <71a80cd4-3a57-47da-90c8-4e79e6b2d7b3@googlegroups.com> |
| In reply to | #103611 |
On Friday, February 10, 2017 at 12:16:55 PM UTC-5, Bart wrote: > I've been trying to find out what the point of 'extern' is. > > Usually, if you declare: > > int abc; > > at filespec ... "file scope"? > ... in modules A and B, then you end up with one copy of 'abc' > shared across both modules. ... "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." (6.9p5). Violating a "shall" that occurs outside of a "Constraints" section has undefined behavior (4p2). Having a single copy of 'abc' shared between the two modules is one of the infinitely many options permitted by "undefined behavior", and a relatively common choice. Another option is that the linking of the program may fail, which is also fairly popular. Other possibilities include having both of them exist, but only one of them can be accessed from other translation units (TUs). The other one would be accessible only from the TU it which it is defined. > ... It doesn't matter which of A or B is abc's > 'home' module. > > If one of them uses 'extern', then it's the same. But it fails when both > use 'extern'. > > Unless one (or both) modules has a second declaration with just 'int > abc;'; that seems to have the effect of cancelling 'extern'. So it must > be doing something, but what? You should define abc in exactly one TU, and you should declare it "extern" in all of the other TUs where it is used. It indicates that the actual definition is in a different TU. That "extern" declaration should be put in a header file, and that header should be #included in every TU that uses 'abc' without defining it. In addition, that header should also be #included in the one TU containing the definition of 'abc'. The standard allows "extern int abc;" and "int abc;" to coexist in the same TU, precisely in order to allow that header to be included. The standard also makes it a constraint violation, with a diagnostic required, if the two declarations don't give 'abc' compatible types. The reason for #including it in the defining TU is so that such a diagnostic will be triggered if a mistake has been made. > When abc is initialised, then this is fine too (unless you initialise > the declaration with 'extern'), but now only one module can initialise > it; initialising both causes link errors. > > It seems that most of the time you can get by without 'extern'. So when > is it necessary? When you care about getting defined behavior when using linkers that work differently from the way you have unjustifiably been expecting them to behave.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2017-02-10 21:10 +0000 |
| Message-ID | <87inoh21ls.fsf@bsb.me.uk> |
| In reply to | #103611 |
BartC <bc@freeuk.com> writes: > I've been trying to find out what the point of 'extern' is. > > Usually, if you declare: > > int abc; > > at filespec in modules A and B, then you end up with one copy of 'abc' > shared across both modules. No, you get undefined behaviour which can show up as a single object. It is common for implementations to merge common definitions during link, but not all of them do and gcc can be asked not to. > If one of them uses 'extern', then it's the same. But it fails when > both use 'extern'. No, then it is correct and that the usual way to write such things: defined in one TU and only declared in another. > Unless one (or both) modules has a second declaration with just 'int > abc;'; that seems to have the effect of cancelling 'extern'. So it > must be doing something, but what? extern is only really significant in that it allows you to write an object declaration rather than a definition. If C had no extern keyword you would not be able to sat "x is an int defined somewhere else": extern int x; // without the extern this is a definition of x It won't prevent a declaration from also being a definition: extern int x = 42; // now a definition because of the initialiser but that's not how it is usually used. <snip> > It seems that most of the time you can get by without 'extern'. So > when is it necessary? To turn a tentative definition into a declaration. -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2017-02-10 13:25 -0800 |
| Message-ID | <08f7edaa-383f-441b-9723-48a37c11c6e9@googlegroups.com> |
| In reply to | #103626 |
On Friday, February 10, 2017 at 3:11:03 PM UTC-6, Ben Bacarisse wrote:
> It won't prevent a declaration from also being a definition:
>
> extern int x = 42; // now a definition because of the initialiser
>
> but that's not how it is usually used.
I wonder if that usage was included to facilitate adaptation of systems which
didn't require that code distinguish between importing and exporting symbols
and thus didn't use "extern" as the means of distinguishing between import
and export. If the length of an array is determined by the data to be stored
therein, that would make it possible to declare and define a symbol in one
place:
extern_if_not_foo_c unsigned char foo[] = { 1,3,5,7,2,4,6,8 };
[with extern_if_not_foo_c being a macro that is defined as "extern" except
when compiling foo.c] and have the compiler figure out the size based upon
the number of initializers would allowed code in any module to use "sizeof"
on the resulting array to determine its length.
[toc] | [prev] | [next] | [standalone]
| From | Andrey Tarasevich <andreytarasevich@hotmail.com> |
|---|---|
| Date | 2017-02-10 14:53 -0800 |
| Message-ID | <o7lg60$df0$1@dont-email.me> |
| In reply to | #103611 |
On 2/10/2017 9:16 AM, BartC wrote:
> I've been trying to find out what the point of 'extern' is.
>
> Usually, if you declare:
>
> int abc;
>
> at filespec in modules A and B, then you end up with one copy of 'abc'
> shared across both modules. It doesn't matter which of A or B is abc's
> 'home' module.
No, you will end up with a constraint violation. C language prohibits
this, although it lists it as a "popular extension" in a non-normative
appendix of the language standard.
(It is often incorrectly claimed that "tentative definition" mechanism
in C allows this. In reality, it doesn't. However, this is allegedly a
side-effect of the approach compilers use to implement tentative
definitions in C. Nevertheless, it is illegal.)
> If one of them uses 'extern', then it's the same.
Then it is correct (as opposed to your previous example).
> But it fails when both use 'extern'.
Certainly, since it leaves your object undefined.
> Unless one (or both) modules has a second declaration with just 'int
> abc;'; that seems to have the effect of cancelling 'extern'. So it must
> be doing something, but what?
See above.
> When abc is initialised, then this is fine too (unless you initialise
> the declaration with 'extern'), but now only one module can initialise
> it; initialising both causes link errors.
Of course. Presence of an initializer makes it into a definition, even
in presence of 'extern'.
> It seems that most of the time you can get by without 'extern'. So when
> is it necessary?
It is necessary to create non-defining declarations of global variables:
extern int i; // Declaration, not a definition
Additionally, it can be used to refer to a hidden name of a global variable
int i;
void foo()
{
int i; // Hides global `i`
{
extern int i; // Refers to global `i` and brings it to
// this scope
...
}
}
-----
As for the declaration-definition model used in standard C, you can take
a look at the description provided in C99 rationale:
"
The definition model to be used for objects with external linkage was a
major C89 standardization issue. The basic problem was to decide which
declarations of an object define storage for the object, and which
merely reference an existing object. A related problem was whether
multiple definitions of storage are allowed, or only one is acceptable.
Pre-C89 implementations exhibit at least four different models, listed
here in order of increasing restrictiveness:
*Common* Every object declaration with external linkage, regardless of
whether the keyword 'extern' appears in the declaration, creates a
definition of storage. When all of the modules are combined together,
each definition with the same name is located at the same address in
memory. (The name is derived from common storage in Fortran.) This model
was the intent of the original designer of C, Dennis Ritchie.
*Relaxed Ref/Def* The appearance of the keyword 'extern' in a
declaration, regardless of whether it is used inside or outside of the
scope of a function, indicates a pure reference (ref), which does not
define storage. Somewhere in all of the translation units, at least one
definition (def) of the object must exist. An external definition is
indicated by an object declaration in file scope containing no storage
class indication. A reference without a corresponding definition is
an error. Some implementations also will not generate a reference for
items which are declared with the 'extern' keyword but are never used in
the code. The UNIX operating system C compiler and linker implement this
model, which is recognized as a common extension to the C language (see
§J.5.11). UNIX C programs which take advantage of this model are
standard conforming in their environment, but are not maximally portable
(not strictly conforming).
*Strict Ref/Def* This is the same as the relaxed ref/def model, save
that only one definition is allowed. Again, some implementations may
decide not to put out references to items that are not used. This is the
model specified in K&R.
*Initialization* This model requires an explicit initialization to
define storage. All other declarations are references.
Figure 6.1 demonstrates the differences between the models.
The Standard model is a combination of features of the strict ref/def
model and the initialization model. As in the strict ref/def model, only
a single translation unit contains the definition of a given object
because many environments cannot effectively or efficiently support the
“distributed definition” inherent in the common or relaxed ref/def
approaches. However, either an initialization, or an appropriate
declaration without storage class specifier (see §6.9), serves as the
external definition. This composite approach was chosen to accommodate
as wide a range of environments and existing implementations as possible.
"
You apparently mistakenly believe that C uses "Common" model, which
admittedly was the original intent of Dennis Ritchie (and probably
existed in C of CRM era), but standard C adopted a different model.
--
Best regards,
Andrey Tarasevich
[toc] | [prev] | [next] | [standalone]
| From | Andrey Tarasevich <andreytarasevich@hotmail.com> |
|---|---|
| Date | 2017-02-10 15:06 -0800 |
| Message-ID | <o7lgtn$ivh$1@dont-email.me> |
| In reply to | #103636 |
On 2/10/2017 2:53 PM, Andrey Tarasevich wrote: >... > As for the declaration-definition model used in standard C, you can take > a look at the description provided in C99 rationale: > > " > The definition model to be used for objects with external linkage was a > major C89 standardization issue. The basic problem was to decide which > declarations of an object define storage for the object, and which > merely reference an existing object. A related problem was whether > multiple definitions of storage are allowed, or only one is acceptable. > Pre-C89 implementations exhibit at least four different models, listed > here in order of increasing restrictiveness: > > *Common* Every object declaration with external linkage, regardless of > whether the keyword 'extern' appears in the declaration, creates a > definition of storage. When all of the modules are combined together, > each definition with the same name is located at the same address in > memory. (The name is derived from common storage in Fortran.) This model > was the intent of the original designer of C, Dennis Ritchie. > > *Relaxed Ref/Def* The appearance of the keyword 'extern' in a > declaration, regardless of whether it is used inside or outside of the > scope of a function, indicates a pure reference (ref), which does not > define storage. Somewhere in all of the translation units, at least one > definition (def) of the object must exist. An external definition is > indicated by an object declaration in file scope containing no storage > class indication. A reference without a corresponding definition is > an error. Some implementations also will not generate a reference for > items which are declared with the 'extern' keyword but are never used in > the code. The UNIX operating system C compiler and linker implement this > model, which is recognized as a common extension to the C language (see > §J.5.11). UNIX C programs which take advantage of this model are > standard conforming in their environment, but are not maximally portable > (not strictly conforming). > > *Strict Ref/Def* This is the same as the relaxed ref/def model, save > that only one definition is allowed. Again, some implementations may > decide not to put out references to items that are not used. This is the > model specified in K&R. > > *Initialization* This model requires an explicit initialization to > define storage. All other declarations are references. > > Figure 6.1 demonstrates the differences between the models. > > The Standard model is a combination of features of the strict ref/def > model and the initialization model. As in the strict ref/def model, only > a single translation unit contains the definition of a given object > because many environments cannot effectively or efficiently support the > “distributed definition” inherent in the common or relaxed ref/def > approaches. However, either an initialization, or an appropriate > declaration without storage class specifier (see §6.9), serves as the > external definition. This composite approach was chosen to accommodate > as wide a range of environments and existing implementations as possible. > " > > You apparently mistakenly believe that C uses "Common" model, which > admittedly was the original intent of Dennis Ritchie (and probably > existed in C of CRM era), but standard C adopted a different model. > A correction: Your description fits the "Relaxed Ref/Def" model, which is also mentioned as a popular extension in the above Rationale. Yet, it is not the model adopted by standard C. -- Best regards, Andrey Tarasevich
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2017-02-10 23:24 +0000 |
| Message-ID | <o7li0r$m52$1@dont-email.me> |
| In reply to | #103636 |
On 10/02/2017 22:53, Andrey Tarasevich wrote:
> On 2/10/2017 9:16 AM, BartC wrote:
>> I've been trying to find out what the point of 'extern' is.
>>
>> Usually, if you declare:
>>
>> int abc;
>>
>> at filespec in modules A and B, then you end up with one copy of 'abc'
>> shared across both modules. It doesn't matter which of A or B is abc's
>> 'home' module.
>
> No, you will end up with a constraint violation. C language prohibits
> this, although it lists it as a "popular extension" in a non-normative
> appendix of the language standard.
>
> (It is often incorrectly claimed that "tentative definition" mechanism
> in C allows this. In reality, it doesn't. However, this is allegedly a
> side-effect of the approach compilers use to implement tentative
> definitions in C. Nevertheless, it is illegal.)
>
>> If one of them uses 'extern', then it's the same.
>
> Then it is correct (as opposed to your previous example).
The 'extern' method is what I use exclusively when my tools
auto-generate C code, as it's the method that more closely matches how I
think about it:
static int A [= expr]; // Defined here, not exported
int B [= expr]; // Defined here, exported
extern int C; // Defined elsewhere, imported
Yet I rarely see 'extern' used in typical C code, and I need to
understand how it's used in other people's code because I want to try
and process C source.
(My generated code doesn't use headers, so if 3 modules want to use 'B'
from my example, and 'B' is defined in module X, then:
X contains: int B; // export
Y contains: extern int B; // import
Z contains: extern int B; // import
Using headers like normal C code, it might be more like this:
X sees: extern int B; // from #include "X.h"
X contains: int B; //
Y sees: extern int B; // from #include "X.h"
Z sees: extern int B; // from #include "X.h"
This combination I can understand. However no one else seems to write C
like I do!)
> Additionally, it can be used to refer to a hidden name of a global variable
>
> int i;
>
> void foo()
> {
> int i; // Hides global `i`
>
> {
> extern int i; // Refers to global `i` and brings it to
> // this scope
> ...
> }
> }
That's an interesting use. But I suspect very little used.
> Pre-C89 implementations exhibit at least four different models, listed
> here in order of increasing restrictiveness:
>
> *Common* Every object declaration with external linkage, regardless of
> whether the keyword 'extern' appears in the declaration, creates a
> definition of storage. When all of the modules are combined together,
> each definition with the same name is located at the same address in
> memory. (The name is derived from common storage in Fortran.) This model
> was the intent of the original designer of C, Dennis Ritchie.
Yes. I liked Fortran...
> *Relaxed Ref/Def* The appearance of the keyword 'extern' in a
> *Strict Ref/Def* This is the same as the relaxed ref/def model, save
> *Initialization* This model requires an explicit initialization to
> define storage. All other declarations are references.
....
This is heavy stuff. But is it really necessary; do linkers really work
like this?
Sure all that's needed is a Local, Imported, Exported model?
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2017-02-11 12:34 +1300 |
| Message-ID | <eg7107Fbmb2U1@mid.individual.net> |
| In reply to | #103643 |
On 02/11/17 12:24 PM, BartC wrote: > The 'extern' method is what I use exclusively when my tools > auto-generate C code, as it's the method that more closely matches how I > think about it: > > static int A [= expr]; // Defined here, not exported > int B [= expr]; // Defined here, exported > extern int C; // Defined elsewhere, imported > > Yet I rarely see 'extern' used in typical C code, and I need to > understand how it's used in other people's code because I want to try > and process C source. > > (My generated code doesn't use headers, so if 3 modules want to use 'B' > from my example, and 'B' is defined in module X, then: > > X contains: int B; // export > Y contains: extern int B; // import > Z contains: extern int B; // import > > Using headers like normal C code, it might be more like this: > > X sees: extern int B; // from #include "X.h" > X contains: int B; // > > Y sees: extern int B; // from #include "X.h" > Z sees: extern int B; // from #include "X.h" > > This combination I can understand. However no one else seems to write C > like I do!) This is the typical use case. -- Ian
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2017-02-13 13:14 +0100 |
| Message-ID | <o7s7rt$rup$1@dont-email.me> |
| In reply to | #103644 |
On 11/02/17 00:34, Ian Collins wrote: > On 02/11/17 12:24 PM, BartC wrote: >> The 'extern' method is what I use exclusively when my tools >> auto-generate C code, as it's the method that more closely matches how I >> think about it: >> >> static int A [= expr]; // Defined here, not exported >> int B [= expr]; // Defined here, exported >> extern int C; // Defined elsewhere, imported >> >> Yet I rarely see 'extern' used in typical C code, and I need to >> understand how it's used in other people's code because I want to try >> and process C source. One good reason why you might not see "extern" so often in code is that it is only needed when data is shared directly amongst translation units, and that is usually considered a bad (or at least risky) practice. And one bad reason is that you (Bart) are not alone in misunderstanding how C linking and definitions work, and in thinking "it seems to work if I do this - it must be the correct way to write the code". >> >> (My generated code doesn't use headers, so if 3 modules want to use 'B' >> from my example, and 'B' is defined in module X, then: >> >> X contains: int B; // export >> Y contains: extern int B; // import >> Z contains: extern int B; // import >> >> Using headers like normal C code, it might be more like this: >> >> X sees: extern int B; // from #include "X.h" >> X contains: int B; // >> >> Y sees: extern int B; // from #include "X.h" >> Z sees: extern int B; // from #include "X.h" >> >> This combination I can understand. However no one else seems to write C >> like I do!) > > This is the typical use case. Yes. Typically you have the "extern" declarations in the header files, and you have the definitions (without "extern" or "static") in the source files. Any definition that does not have a matching "extern" declaration in an appropriate header, should be marked "static". Personally, I also put "extern" in my function declarations in headers. It is not required (since the lack of a function body already marks it as a non-defining declaration), and many people don't use it, but I feel it gives a clearer indication that this is a "global" function.
[toc] | [prev] | [next] | [standalone]
| From | GOTHIER Nathan <nathan.gothier@gmail.com> |
|---|---|
| Date | 2017-02-13 13:44 +0100 |
| Message-ID | <20170213134423.3e115bb6b08b18a261c46bae@gmail.com> |
| In reply to | #103789 |
On Mon, 13 Feb 2017 13:14:34 +0100 David Brown <david.brown@hesbynett.no> wrote: > One good reason why you might not see "extern" so often in code is that > it is only needed when data is shared directly amongst translation > units, and that is usually considered a bad (or at least risky) > practice. And one bad reason is that you (Bart) are not alone in > misunderstanding how C linking and definitions work, and in thinking "it > seems to work if I do this - it must be the correct way to write the code". I agree the linkage definition is rather obscure in the C standard. > Yes. Typically you have the "extern" declarations in the header files, > and you have the definitions (without "extern" or "static") in the > source files. Any definition that does not have a matching "extern" > declaration in an appropriate header, should be marked "static". If you put a non "extern" object with "static", its lifetime is longer than necessary and you prevent the compiler to free unused memory space for example when leaving a block. The linkage defines links between objects like pointers. It is useful to distinguish objects named with the same identifier. > Personally, I also put "extern" in my function declarations in headers. > It is not required (since the lack of a function body already marks it > as a non-defining declaration), and many people don't use it, but I feel > it gives a clearer indication that this is a "global" function. Prototypes should always be declared as "extern" since it points to a previous definition.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2017-02-13 14:13 +0000 |
| Message-ID | <87fujitbzn.fsf@bsb.me.uk> |
| In reply to | #103790 |
GOTHIER Nathan <nathan.gothier@gmail.com> writes: > On Mon, 13 Feb 2017 13:14:34 +0100 > David Brown <david.brown@hesbynett.no> wrote: <snip> >> Personally, I also put "extern" in my function declarations in headers. >> It is not required (since the lack of a function body already marks it >> as a non-defining declaration), and many people don't use it, but I feel >> it gives a clearer indication that this is a "global" function. > > Prototypes should always be declared as "extern" since it points to a previous > definition. I have a feeling that it is more common to leave extern off from prototype declarations. Even if it's not as common as I imagine, I would expect everyone reading C to be used to it. In short, I think a blank "should" is too strong. -- Ben.
[toc] | [prev] | [next] | [standalone]
Page 2 of 6 — ← Prev page 1 [2] 3 4 5 6 Next page →
Back to top | Article view | comp.lang.c
csiph-web