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


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

Style question: Declaration of globals in header file

Started bySteve Keller <keller@no.invalid>
First post2017-06-06 19:33 +0200
Last post2017-06-09 09:52 -0700
Articles 17 on this page of 37 — 15 participants

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


Contents

  Style question: Declaration of globals in header file Steve Keller <keller@no.invalid> - 2017-06-06 19:33 +0200
    Re: Style question: Declaration of globals in header file "James R. Kuyper" <jameskuyper@verizon.net> - 2017-06-06 14:21 -0400
      Re: Style question: Declaration of globals in header file Steve Keller <keller@no.invalid> - 2017-06-12 11:07 +0200
        Re: Style question: Declaration of globals in header file bartc <bc@freeuk.com> - 2017-06-12 11:03 +0100
        Re: Style question: Declaration of globals in header file Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-06-12 11:40 +0100
        Re: Style question: Declaration of globals in header file James Kuyper <jameskuyper@verizon.net> - 2017-06-12 07:33 -0400
          Re: Style question: Declaration of globals in header file Steve Keller <keller@no.invalid> - 2017-06-12 18:00 +0200
            Re: Style question: Declaration of globals in header file "James R. Kuyper" <jameskuyper@verizon.net> - 2017-06-12 12:11 -0400
              Re: Style question: Declaration of globals in header file Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-06-12 17:27 +0100
            Re: Style question: Declaration of globals in header file Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-06-12 17:18 +0100
            Re: Style question: Declaration of globals in header file supercat@casperkitty.com - 2017-06-12 09:44 -0700
        Re: Style question: Declaration of globals in header file supercat@casperkitty.com - 2017-06-12 07:55 -0700
          Re: Style question: Declaration of globals in header file Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-06-12 16:51 +0100
    Re: Style question: Declaration of globals in header file Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-06-06 19:21 +0100
    Re: Style question: Declaration of globals in header file Jorgen Grahn <grahn+nntp@snipabacken.se> - 2017-06-06 19:54 +0000
    Re: Style question: Declaration of globals in header file Andrey Tarasevich <andreytarasevich@hotmail.com> - 2017-06-06 18:37 -0700
      Re: Style question: Declaration of globals in header file supercat@casperkitty.com - 2017-06-07 07:54 -0700
        Re: Style question: Declaration of globals in header file David Brown <david.brown@hesbynett.no> - 2017-06-07 17:23 +0200
          Re: Style question: Declaration of globals in header file supercat@casperkitty.com - 2017-06-07 11:10 -0700
            Re: Style question: Declaration of globals in header file David Brown <david.brown@hesbynett.no> - 2017-06-07 22:13 +0200
              Re: Style question: Declaration of globals in header file supercat@casperkitty.com - 2017-06-07 14:57 -0700
                Re: Style question: Declaration of globals in header file David Brown <david.brown@hesbynett.no> - 2017-06-08 00:05 +0200
                Re: Style question: Declaration of globals in header file bartc <bc@freeuk.com> - 2017-06-07 23:19 +0100
                  Re: Style question: Declaration of globals in header file supercat@casperkitty.com - 2017-06-07 16:16 -0700
                Re: Style question: Declaration of globals in header file Ian Collins <ian-news@hotmail.com> - 2017-06-08 12:56 +1200
                  Re: Style question: Declaration of globals in header file David Brown <david.brown@hesbynett.no> - 2017-06-08 08:51 +0200
                    Re: Style question: Declaration of globals in header file David Thompson <dave.thompson2@verizon.net> - 2017-07-09 22:43 -0400
                      Re: Style question: Declaration of globals in header file supercat@casperkitty.com - 2017-07-10 08:46 -0700
                        Re: Style question: Declaration of globals in header file Robert Wessel <robertwessel2@yahoo.com> - 2017-07-10 21:00 -0500
                          Re: Style question: Declaration of globals in header file supercat@casperkitty.com - 2017-07-10 21:08 -0700
                            Re: Style question: Declaration of globals in header file Robert Wessel <robertwessel2@yahoo.com> - 2017-07-11 01:18 -0500
                  Re: Style question: Declaration of globals in header file bartc <bc@freeuk.com> - 2017-06-08 10:10 +0100
                  Re: Style question: Declaration of globals in header file raltbos@xs4all.nl (Richard Bos) - 2017-06-17 18:08 +0000
              Re: Style question: Declaration of globals in header file "Patrick.Schluter" <Patrick.Schluter@free.fr> - 2017-06-10 08:36 +0200
      Re: Style question: Declaration of globals in header file Tim Rentsch <txr@alumni.caltech.edu> - 2017-06-09 10:09 -0700
        Re: Style question: Declaration of globals in header file supercat@casperkitty.com - 2017-06-09 12:17 -0700
    Re: Style question: Declaration of globals in header file Tim Rentsch <txr@alumni.caltech.edu> - 2017-06-09 09:52 -0700

Page 2 of 2 — ← Prev page 1 [2]


#111759

Fromsupercat@casperkitty.com
Date2017-06-07 14:57 -0700
Message-ID<b653ad2b-9822-456d-93fc-97427e1b73e8@googlegroups.com>
In reply to#111753
On Wednesday, June 7, 2017 at 3:13:50 PM UTC-5, David Brown wrote:
> On 07/06/17 20:10, supercat wrote:
> > The FOO_C macro would only be defined within FOO_C, and (while I forgot
> > to mention it) the varqual macro should be undef'ed at the end, or else
> > a module-specific name (FOO_VARQUAL) used instead.  The pattern avoids
> > the need to have the source text contain two separate declarations for
> > each variable that is shared between compilation units. 
> 
> If you think that is a problem, you have serious issues with your 
> development practices.  Declare the exported symbol in the header, and 
> define it in /one/ C file.  Make sure you include the header in the C 
> file, and the compiler will tell you if they are out of synchronisation. 

In most cases the compiler will squawk if they get out of sync, but there
are some situations where it may not, such as when the number of
initializers falls short of the size of an array.

How many languages can you think of besides C and C++ which require that
variables be declared in two places?  Popular versions of Pascal required
that for exported functions headers (the interface portion of a source
text would contain just the header, and that header would be appear again
at the function definition) but I don't recall them requiring that for
exported variables.

In cases where a compiler could easily validate everything it needs to
ensure that things stay in sync I generally use the common idiom not
because I think it's the best, but because it's common.  In cases where
information needed for an initialization ties in with other information
in a header, however, I prefer to keep related things together.

>   And if you are changing your global data so often that separate 
> declarations and definitions are inconvenient, then your should scrap 
> your program design and start again.

Most such things don't change terribly often, but I believe keeping related
things together is more important.  Having a header file contain:

   enum woozle_states {ws_start, ws_init, ws_idle, ws_triggered};

and then having another file contain

   char const *woozle_state_names[] = {"start", "init", "idle", "triggered"};

will make it hard for anyone inspecting the code to ensure that the two
lists stay in sync.  Having such things near each other in the same file
will make visual inspection much easier.

> It is a /bad/ idea to make the same section of code have different 
> effects at different times in the same program, due to pre-processor 
> symbol definitions.  There are occasional uses, such as "x macros", but 
> these should be used carefully and clearly.  It is far better if any 
> given section of code in a header or a C file has the same meaning all 
> the time in the given program build.

Rather than complaining about preprocessor hackery, it might be better to
either complain about the language shortcomings that drive programmers to
use such things, or else regard such hackery as providing an adequate
workaround for those shortcomings that there's no need to eliminate them.

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


#111760

FromDavid Brown <david.brown@hesbynett.no>
Date2017-06-08 00:05 +0200
Message-ID<oh9t50$odp$1@dont-email.me>
In reply to#111759
On 07/06/17 23:57, supercat@casperkitty.com wrote:
> On Wednesday, June 7, 2017 at 3:13:50 PM UTC-5, David Brown wrote:
>> On 07/06/17 20:10, supercat wrote:
>>> The FOO_C macro would only be defined within FOO_C, and (while I forgot
>>> to mention it) the varqual macro should be undef'ed at the end, or else
>>> a module-specific name (FOO_VARQUAL) used instead.  The pattern avoids
>>> the need to have the source text contain two separate declarations for
>>> each variable that is shared between compilation units.
>>
>> If you think that is a problem, you have serious issues with your
>> development practices.  Declare the exported symbol in the header, and
>> define it in /one/ C file.  Make sure you include the header in the C
>> file, and the compiler will tell you if they are out of synchronisation.
> 
> In most cases the compiler will squawk if they get out of sync, but there
> are some situations where it may not, such as when the number of
> initializers falls short of the size of an array.
> 
> How many languages can you think of besides C and C++ which require that
> variables be declared in two places?  Popular versions of Pascal required
> that for exported functions headers (the interface portion of a source
> text would contain just the header, and that header would be appear again
> at the function definition) but I don't recall them requiring that for
> exported variables.
> 
> In cases where a compiler could easily validate everything it needs to
> ensure that things stay in sync I generally use the common idiom not
> because I think it's the best, but because it's common.  In cases where
> information needed for an initialization ties in with other information
> in a header, however, I prefer to keep related things together.
> 
>>    And if you are changing your global data so often that separate
>> declarations and definitions are inconvenient, then your should scrap
>> your program design and start again.
> 
> Most such things don't change terribly often, but I believe keeping related
> things together is more important.  Having a header file contain:
> 
>     enum woozle_states {ws_start, ws_init, ws_idle, ws_triggered};
> 
> and then having another file contain
> 
>     char const *woozle_state_names[] = {"start", "init", "idle", "triggered"};

You can write "static const char * const woozle_state_names[] = ..." in 
the header if you want.  Unless you are using it in many different 
modules, it should not mean much wasted space.  (And with gcc's 
non-conforming "-fmerge-all-constants" option, it will take no extra 
space at all.)

> 
> will make it hard for anyone inspecting the code to ensure that the two
> lists stay in sync.  Having such things near each other in the same file
> will make visual inspection much easier.
> 
>> It is a /bad/ idea to make the same section of code have different
>> effects at different times in the same program, due to pre-processor
>> symbol definitions.  There are occasional uses, such as "x macros", but
>> these should be used carefully and clearly.  It is far better if any
>> given section of code in a header or a C file has the same meaning all
>> the time in the given program build.
> 
> Rather than complaining about preprocessor hackery, it might be better to
> either complain about the language shortcomings that drive programmers to
> use such things, or else regard such hackery as providing an adequate
> workaround for those shortcomings that there's no need to eliminate them.
> 

Perhaps you should switch to C++17 - inline variables should solve all 
your problems here.

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


#111763

Frombartc <bc@freeuk.com>
Date2017-06-07 23:19 +0100
Message-ID<UZ_ZA.163507$Rw1.51473@fx44.am4>
In reply to#111759
On 07/06/2017 22:57, supercat@casperkitty.com wrote:
> On Wednesday, June 7, 2017 at 3:13:50 PM UTC-5, David Brown wrote:

>> If you think that is a problem, you have serious issues with your
>> development practices.  Declare the exported symbol in the header, and
>> define it in /one/ C file.  Make sure you include the header in the C
>> file, and the compiler will tell you if they are out of synchronisation.
> 
> In most cases the compiler will squawk if they get out of sync, but there
> are some situations where it may not, such as when the number of
> initializers falls short of the size of an array.
> 
> How many languages can you think of besides C and C++ which require that
> variables be declared in two places?

Some of mine did for a quite a long time. And it /was/ a nuisance.

Only in the last few years have I used a module import system, and it's 
gorgeous to use.

Say Module A exports some things. For modules B and C to import them, 
they each need 'import A' at the start, that's all.

Inside A, if I decide another function (or variable, named constant, 
typedef, enum, or struct) should be exported, I just stick 'global' in 
front.

That's it.

(Duplicate declarations also come up with forward function declarations. 
That's taken care of with a different mechanism. Result: functions, even 
local ones, can be placed anywhere, juggled about, or copied across 
projects, without worrying about declaring them at the start.)

> Rather than complaining about preprocessor hackery, it might be better to
> either complain about the language shortcomings that drive programmers to
> use such things,

Apparently that doesn't work. People who use the language for serious 
purposes can only use what's available now, they haven't got time to sit 
back and think about making something better. Or they just switch to C++.


-- 
bartc

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


#111767

Fromsupercat@casperkitty.com
Date2017-06-07 16:16 -0700
Message-ID<6a0b1a60-3352-4c11-96ed-e6ac4fd00709@googlegroups.com>
In reply to#111763
On Wednesday, June 7, 2017 at 5:19:40 PM UTC-5, Bart wrote:
> On 07/06/2017 22:57, supercat wrote:
> > Rather than complaining about preprocessor hackery, it might be better to
> > either complain about the language shortcomings that drive programmers to
> > use such things,
> 
> Apparently that doesn't work. People who use the language for serious 
> purposes can only use what's available now, they haven't got time to sit 
> back and think about making something better. Or they just switch to C++.

Or they use macro hacks to achieve the semantics that they need, to the
apparent dismay of people who like to complain about such hacks.

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


#111777

FromIan Collins <ian-news@hotmail.com>
Date2017-06-08 12:56 +1200
Message-ID<eprll7Fb6agU3@mid.individual.net>
In reply to#111759
On 06/ 8/17 09:57 AM, supercat@casperkitty.com wrote:
>
> How many languages can you think of besides C and C++ which require that
> variables be declared in two places?

That subset of languages is about to shrink to one...

C++ inline variables Would be a good fit in C as well.

-- 
Ian

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


#111797

FromDavid Brown <david.brown@hesbynett.no>
Date2017-06-08 08:51 +0200
Message-ID<ohartu$3ub$1@dont-email.me>
In reply to#111777
On 08/06/17 02:56, Ian Collins wrote:
> On 06/ 8/17 09:57 AM, supercat@casperkitty.com wrote:
>>
>> How many languages can you think of besides C and C++ which require that
>> variables be declared in two places?
> 
> That subset of languages is about to shrink to one...
> 
> C++ inline variables Would be a good fit in C as well.
> 

Modula 2 has a clean separation between the interface and the
implementation of a module - it requires global data to be declared once
and then defined later in two separate files.  Pascal and Ada both
require them twice too.

I think C++ inline variables are a nice idea, but a horrendous choice of
names.  Yes, they share some aspects of inline functions - but not those
aspects that give them the name "inline".


In C programming, how often is it a good idea to have exported global
variables?  You can find endless style guides, tutorials, and other
recommendations telling you to avoid them as much as possible - very few
that say they are a good idea.  (I think they /can/ be a good idea,
especially when writing small programs for small systems, trying to have
as efficient code as possible, and when the whole program is under the
control of one programmer.  Those are quite restrictive circumstances.)

So really, what are we arguing about?  The effort involving in writing
an extra line of header code for a feature that we usually try to avoid
anyway?

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


#113481

FromDavid Thompson <dave.thompson2@verizon.net>
Date2017-07-09 22:43 -0400
Message-ID<fcq5mc57esntaf6l23o8b9h42asvji0t6k@4ax.com>
In reply to#111797
On Thu, 08 Jun 2017 08:51:00 +0200, David Brown
<david.brown@hesbynett.no> wrote:

> On 08/06/17 02:56, Ian Collins wrote:
> > On 06/ 8/17 09:57 AM, supercat@casperkitty.com wrote:
> >>
> >> How many languages can you think of besides C and C++ which require that
> >> variables be declared in two places?

> Modula 2 has a clean separation between the interface and the
> implementation of a module - it requires global data to be declared once
> and then defined later in two separate files.  Pascal and Ada both
> require them twice too.
> 
Ada permits a shared variable to be declared only once, in the public
part of a package spec, if everything needed in the declaration (like
types and values) is available publicly. But even when possible it may
be considered better style to 'hide' it in the private part of the
spec or the body, and in other cases it's necessary.

Ada itself says nothing about putting source in files, and in fact
some implementations didn't use _any_ files, but _one_ currently
popular implementation, GNAT (part of GCC and free both gratis and
libre), does require each compilation-unit in a separate source file,
including spec vs body but not public vs private in spec.

Original FORTRAN required COMMON blocks be (re)declared in each
progam-unit, and mistakes in doing so were common enough quite a few
tools were written to catch them; in F90+ MODULEs are written once
(which constrains compilation order). PL/I and COBOL used to duplicate
the declarations, often using COPY or %INCLUDE; I haven't kept track
if either has changed recently. Both standard algols evaded the issue
by not admitting separate compilation; I don't know implementations.

SQL, if you count it as programming, doesn't re-declare because
metadata is in a catalog.

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


#113516

Fromsupercat@casperkitty.com
Date2017-07-10 08:46 -0700
Message-ID<2f70d6e4-d11a-4e9c-9a39-175a2653dc97@googlegroups.com>
In reply to#113481
On Sunday, July 9, 2017 at 9:44:04 PM UTC-5, David Thompson wrote:
> Original FORTRAN required COMMON blocks be (re)declared in each
> progam-unit, and mistakes in doing so were common enough quite a few
> tools were written to catch them; in F90+ MODULEs are written once
> (which constrains compilation order). PL/I and COBOL used to duplicate
> the declarations, often using COPY or %INCLUDE; I haven't kept track
> if either has changed recently. Both standard algols evaded the issue
> by not admitting separate compilation; I don't know implementations.

Given a choice between passing programs through an extra "link" stage,
versus requiring that programmers use matching "common" directives in
every module, I think a lot of machine owners would have much preferred
the latter.

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


#113581

FromRobert Wessel <robertwessel2@yahoo.com>
Date2017-07-10 21:00 -0500
Message-ID<c8c8mc1ndqfc7lrvvthl14jpiqbrrauk3q@4ax.com>
In reply to#113516
On Mon, 10 Jul 2017 08:46:45 -0700 (PDT), supercat@casperkitty.com
wrote:

>On Sunday, July 9, 2017 at 9:44:04 PM UTC-5, David Thompson wrote:
>> Original FORTRAN required COMMON blocks be (re)declared in each
>> progam-unit, and mistakes in doing so were common enough quite a few
>> tools were written to catch them; in F90+ MODULEs are written once
>> (which constrains compilation order). PL/I and COBOL used to duplicate
>> the declarations, often using COPY or %INCLUDE; I haven't kept track
>> if either has changed recently. Both standard algols evaded the issue
>> by not admitting separate compilation; I don't know implementations.
>
>Given a choice between passing programs through an extra "link" stage,
>versus requiring that programmers use matching "common" directives in
>every module, I think a lot of machine owners would have much preferred
>the latter.


Eh?  The programs with the common areas were almost always linked
together.

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


#113594

Fromsupercat@casperkitty.com
Date2017-07-10 21:08 -0700
Message-ID<4b9e9f7e-f225-4f56-b542-08ef509e5334@googlegroups.com>
In reply to#113581
On Monday, July 10, 2017 at 9:00:44 PM UTC-5, robert...@yahoo.com wrote:
> On Mon, 10 Jul 2017 08:46:45 -0700 (PDT), supercat wrote:
> 
> >On Sunday, July 9, 2017 at 9:44:04 PM UTC-5, David Thompson wrote:
> >> Original FORTRAN required COMMON blocks be (re)declared in each
> >> progam-unit, and mistakes in doing so were common enough quite a few
> >> tools were written to catch them; in F90+ MODULEs are written once
> >> (which constrains compilation order). PL/I and COBOL used to duplicate
> >> the declarations, often using COPY or %INCLUDE; I haven't kept track
> >> if either has changed recently. Both standard algols evaded the issue
> >> by not admitting separate compilation; I don't know implementations.
> >
> >Given a choice between passing programs through an extra "link" stage,
> >versus requiring that programmers use matching "common" directives in
> >every module, I think a lot of machine owners would have much preferred
> >the latter.
> 
> Eh?  The programs with the common areas were almost always linked
> together.

Were they linked using a symbolic linker that could apply address fixups,
or were they simply loaded into memory simultaneously?  If the latter, would
that require a separate "link" stage, or could it simply be done when the
code was loaded?

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


#113599

FromRobert Wessel <robertwessel2@yahoo.com>
Date2017-07-11 01:18 -0500
Message-ID<m0q8mcpumhs430f9ccca1oa62v29j7n9vn@4ax.com>
In reply to#113594
On Mon, 10 Jul 2017 21:08:47 -0700 (PDT), supercat@casperkitty.com
wrote:

>On Monday, July 10, 2017 at 9:00:44 PM UTC-5, robert...@yahoo.com wrote:
>> On Mon, 10 Jul 2017 08:46:45 -0700 (PDT), supercat wrote:
>> 
>> >On Sunday, July 9, 2017 at 9:44:04 PM UTC-5, David Thompson wrote:
>> >> Original FORTRAN required COMMON blocks be (re)declared in each
>> >> progam-unit, and mistakes in doing so were common enough quite a few
>> >> tools were written to catch them; in F90+ MODULEs are written once
>> >> (which constrains compilation order). PL/I and COBOL used to duplicate
>> >> the declarations, often using COPY or %INCLUDE; I haven't kept track
>> >> if either has changed recently. Both standard algols evaded the issue
>> >> by not admitting separate compilation; I don't know implementations.
>> >
>> >Given a choice between passing programs through an extra "link" stage,
>> >versus requiring that programmers use matching "common" directives in
>> >every module, I think a lot of machine owners would have much preferred
>> >the latter.
>> 
>> Eh?  The programs with the common areas were almost always linked
>> together.
>
>Were they linked using a symbolic linker that could apply address fixups,
>or were they simply loaded into memory simultaneously?  If the latter, would
>that require a separate "link" stage, or could it simply be done when the
>code was loaded?


You usually had a symbolic linker.  In some cases (several of the 14xx
compilers) it was actually a runtime loader, but it would resolve
addresses between the included modules.  I think all the S/360
Fortrans just used the system linker after normal compile steps, and
created an executable file (although you could run that immediately
after the link, and not actually save it to a library).   Most early
Fortrans also supported a form of overlay, and allowed COMMON storage
to persist between overlaid segments.

You could also define FUNCTIONS and SUBROUTINES in the same source
module (although they mostly shared nothing with each other, except
via the COMMON area).

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


#111801

Frombartc <bc@freeuk.com>
Date2017-06-08 10:10 +0100
Message-ID<8w8_A.425868$C56.370903@fx34.am4>
In reply to#111777
On 08/06/2017 01:56, Ian Collins wrote:
> On 06/ 8/17 09:57 AM, supercat@casperkitty.com wrote:
>>
>> How many languages can you think of besides C and C++ which require that
>> variables be declared in two places?
> 
> That subset of languages is about to shrink to one...

> C++ inline variables Would be a good fit in C as well.

Not a good sign when you have to go online to find out what they mean...

So an inline variable is one that is declared in a header, but there is 
some mechanism so that multiple definitions don't result.

Although if it is defined with a hundred lines of initialisation data, 
that data will be recompiled in each module. (And any dependencies 
within that data will also need to be shared.)

It also sounds like such a variable doesn't have a 'home' module (maybe 
a 'header'). And that there might be problems when two modules want to 
export the same named variable (C has this too, but C++ is supposed to 
be better, right?)

And it doesn't sound like it eliminates the need for a separate module 
and header. So when you need a new global, so you have to go and edit 
another file.

Does it apply to functions too? I thought I read that. So the entire 
function body needs to move into the header? That can't be right. So 
effectively, source files are eliminated; we just have headers. That 
will solve the problem of editing two files anyway!

But if there is still source file and header, then half the functions 
and variables will be in the header, and half in the module.

Except, that can't work. Suppose the shared, inline function in the 
header, needs to call a local function in the home module? Another 
module including this header won't see that function.

For that matter, how does C++ cope with the problem of functions f() and 
g() calling each other, even in the same module? C requires that at 
least one of those has a forward declaration (ie. needs declaring twice).

-- 
bartc

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


#112403

Fromraltbos@xs4all.nl (Richard Bos)
Date2017-06-17 18:08 +0000
Message-ID<59456fc7.1007437@news.xs4all.nl>
In reply to#111777
Ian Collins <ian-news@hotmail.com> wrote:

> On 06/ 8/17 09:57 AM, supercat@casperkitty.com wrote:
> >
> > How many languages can you think of besides C and C++ which require that
> > variables be declared in two places?
> 
> That subset of languages is about to shrink to one...
> 
> C++ inline variables Would be a good fit in C as well.

I haven't studied them in detail, but for now I fail to see what they
bring that an ordinary static declaration couldn't, except allow for
more sloppiness in declarations in other parts of the program - which I
would want to dis- rather than encourage.

Richard

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


#111919

From"Patrick.Schluter" <Patrick.Schluter@free.fr>
Date2017-06-10 08:36 +0200
Message-ID<593b937d$0$8852$426a74cc@news.free.fr>
In reply to#111753
Le 07.06.2017 à 22:13, David Brown a écrit :
> On 07/06/17 20:10, supercat@casperkitty.com wrote:
>> On Wednesday, June 7, 2017 at 10:24:00 AM UTC-5, David Brown wrote:
>>> On 07/06/17 16:54, supercat wrote:
>>>> Another variation is:
>>>>
>>>> --foo.h
>>>> #ifdef FOO_C
>>>> #define varqual
>>>> #else
>>>> #define varqual extern
>>>> #endif
>>>> varqual int foo;
>>>>
>>>> --foo.c
>>>> #define FOO_C
>>>> #include "foo.h"
>>>>
>>>> This has the advantage of avoiding redundant declarations.
>>>
>>> This is, IMHO, a hideous way of exporting your variables.  I /really/
>>> hate it when include files are not "stand alone" but depend on different
>>> values of #define'd macros, ordering of #include files, number of times
>>> included, etc.
>>
>> The FOO_C macro would only be defined within FOO_C, and (while I forgot
>> to mention it) the varqual macro should be undef'ed at the end, or else
>> a module-specific name (FOO_VARQUAL) used instead.  The pattern avoids
>> the need to have the source text contain two separate declarations for
>> each variable that is shared between compilation units. 
> 
> If you think that is a problem, you have serious issues with your 
> development practices.  Declare the exported symbol in the header, and 
> define it in /one/ C file.  Make sure you include the header in the C 
> file, and the compiler will tell you if they are out of synchronisation. 
>   And if you are changing your global data so often that separate 
> declarations and definitions are inconvenient, then your should scrap 
> your program design and start again.

+1 I always wonder why people deviate from that model as it is exactly 
the same with functions. Declare in the header with a prototype and 
define in only one C file. Doing the extern in header and the initialise 
definition in the C file uses the exact same pattern.

> 
> It is a /bad/ idea to make the same section of code have different 
> effects at different times in the same program, due to pre-processor 
> symbol definitions.  There are occasional uses, such as "x macros", but 
> these should be used carefully and clearly.  It is far better if any 
> given section of code in a header or a C file has the same meaning all 
> the time in the given program build.

+1. Again, one might not see it when a program is made out of 2 header 
and 2 C files, but inheriting a project with 300K lines, with around 50 
header files, it is vital to have idempotent header files or else the 
project becomes a ball of mud completely unamendable. It is already a 
problem with inlines which forces one to do this kind of acrobatics, 
adding the variable declarations to it would be suicidal.

> 
>> Further, in cases
>> where multiple modules will need to know the size of an exported table of
>> constants, I would think it much safer to have both the size and the
>> contents in the same (header) file, than to have the size in a header 
>> file
>> but the contents in a separate source file. 
> 
> Nonsense.  How often might this be useful?  Once in a program?  Is that 
> enough to spoil the rest of your code with a throwback from the nineties?
> 
>> Given, e.g.
>>
>> foo.h
>>      #define NUM_WIDGETS 4
>>      extern unsigned widgets[NUM_WIDGETS];
>> foo.c
>>      #include <foo.h>
>>      unsigned widgets[NUM_WIDGETS] = {1,2,3,4};
>>
>> there would be no validation to ensure that foo.h and foo.c remain in 
>> sync.
> 
> First, you easily get validation against having too many initialisers. 
> Checking against too few is harder - but easy to do during development 
> (just add another, and see that you get a compile-time error).  Given 
> that this is a sort of construct that you would rarely need in 
> situations where you have so many initialisers that it is likely for you 
> to make a mistake, it simply is not worth making an exception for it.

or he could put a CompilerAssert(NUM_WIDGETS == 4); in his foo.c . The 
macro that generated so much bewilderment (bartc) last week in another 
thread.

> 
> And if you really want to have compile-time checking of the number of 
> initialisers, that is easy to do with a trick that works for any array 
> initialisation (not just exported arrays):
> 
> 
> #define WIDGETS_INIT { 1, 2, 3, 4 }
> _Static_assert(sizeof((unsigned []) WIDGETS_INIT) == NUM_WIDGETS *
>               sizeof(unsigned), "Bad size");
> unsigned widgets[] = WIDGETS_INIT;
> 
> 
>> If a version of foo.h which is intended for 5 widgets gets used with a
>> version of foo.c that only defines those four values, no diagnostic would
>> be produced, but everything including foo.c would think there were five
>> widgets numbered {1,2,3,4,0} rather than four.
>>
> 
> If you use a version of foo.h that is out of sync with foo.c like that, 
> you have plenty of other problems to think about.

+1

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


#111894

FromTim Rentsch <txr@alumni.caltech.edu>
Date2017-06-09 10:09 -0700
Message-ID<kfnvao59jgv.fsf@x-alumni2.alumni.caltech.edu>
In reply to#111669
Andrey Tarasevich <andreytarasevich@hotmail.com> writes:

> On 6/6/2017 10:33 AM, Steve Keller wrote:
>> The C standard allows the
>> declarations in the header file to be with or without the extern
>> storage class specifier, i.e. one could write
>>
>>     -- foo.h --
>>     int foo;
>>     int bar;
>>     -- foo.c --
>>     #include "foo.h"
>>
>>     int bar = 1;
>>     ...
>>     -----------
>
> Nope.  C standard does not allow that, assuming that you include this
> header file into multiple translation units.

Not exactly right.  The Standard does allow it, but doesn't make
any guarantees about what it will do or whether it will work.
It can work just fine if an implementation chooses to make that
happen.

Historical note:  my understanding is this is how C was normally
written, back in the dark ages (ie, before circa 1985ish).  That
may be worth keeping in mind when reading old C code, even though
now the normal practice is decidedly different.

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


#111901

Fromsupercat@casperkitty.com
Date2017-06-09 12:17 -0700
Message-ID<1d33c21c-64a1-44b7-b5a5-2c1365d27be4@googlegroups.com>
In reply to#111894
On Friday, June 9, 2017 at 12:09:12 PM UTC-5, Tim Rentsch wrote:
> Historical note:  my understanding is this is how C was normally
> written, back in the dark ages (ie, before circa 1985ish).  That
> may be worth keeping in mind when reading old C code, even though
> now the normal practice is decidedly different.

Different systems use different object file formats and linkers.  Some
formats make no distinction between exported and imported symbols, and
will silently merge definitions that appear to be compatible.  Others
require that every symbol that is imported anyplace must be be marked as
exported in exactly one object file.  Others allow for symbols to be
marked as "strong" or "weak", and will silently merge duplicate weak
definitions but only allow one "strong" one (which will take precedence
if it exists).

While it would be useful to have the language to offer semantic
guarantees on systems whose linkers can support them, one of the major
advantages C has over some other languages (including C++) is the range
of object/linking systems with which it can be used.  In general, if a
C compiler is used with a linker that silently merges duplicate
definitions, it will tolerate variables that are exported by multiple
source files.  If a compiler is used with a linker that requires that
every symbol be exported exactly once, that requirement will apply to
the C source code.

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


#111893

FromTim Rentsch <txr@alumni.caltech.edu>
Date2017-06-09 09:52 -0700
Message-ID<kfnzidh9k95.fsf@x-alumni2.alumni.caltech.edu>
In reply to#111644
Steve Keller <keller@no.invalid> writes:

> How do you define & declare global variables in implementation and
> header files?  [...] one could write
>
>     -- foo.h --
>     int foo;
>     int bar;
>     -- foo.c --
>     #include "foo.h"
>
>     int bar = 1;
>     ...
>     -----------
>
> or
>
>     -- foo.h --
>     extern int foo;
>     extern int bar;
>     -- foo.c --
>     #include "foo.h"
>
>     int foo;
>     int bar = 1;
>     ...
>     -----------

The first pattern probably does work in some implementations,
definitely does not work in others, and is not required to work
in any way shape or form in any implementation.  (This assuming
"foo.h" is included in more than one translation unit.)

The second pattern works in all implementations that conform to
the Standard.

Do I need to state the obvious conclusion?

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

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


csiph-web