Handling 'initializer element not constant' error

Discussion in 'C Programming' started by Gowtham, May 7, 2008.

  1. Gowtham

    Gowtham Guest

    Hi,

    I had some C code written which initialized a global variable as:

    FILE *yyerfp = stdout;

    This used to work fine in older versions of gcc. Now, when I tried to
    compile this code (with gcc 3.2.3),
    I got errors like:

    .../Include/Message.h:42: initializer element is not constant

    I looked around the www and found that stdin/stdout/stderr are *not*
    made const in the newer
    versions of gcc.

    As a work-around, I thought of this:

    FILE *yyerfp; // Uninitialized global

    // Initialize it in a separate function
    void initializeGlobals( void )
    {
    yyerfp = stdout;
    }

    int main( ... )
    {
    // Initialize the global before doing anything else
    initializeGlobals();
    ...
    // Do other things
    }

    But, this code will also be compiled into a shared object, dynamically
    loadable from other
    languages such as perl etc. and I do not want to change the API
    interface there. If I follow
    this approach, I also have to add the initializeGlobals() call in
    every perl program which uses
    this library.

    What is the best way of solving this problem?

    Thanks
    Gowtham
     
    Gowtham, May 7, 2008
    #1
    1. Advertising

  2. Gowtham

    viza Guest

    Hi

    On May 7, 3:14 pm, Gowtham <> wrote:

    > I had some C code written which initialized a global variable as:
    >
    > FILE *yyerfp = stdout;
    > ...
    > But, this code will also be compiled into a shared object
    > ...
    > What is the best way of solving this problem?


    The correct and best way to solve this problem is to remember that
    library functions should not write to the standard streams.

    Imagine that stdin, stdout and stderr are local variables within
    main(). Any library function that needs to write to a file should
    take a pointer to one as an argument. The author of main() can then
    pass stdout *if* they give you permission to write to it.

    This makes your code more modular and easier to reuse, it makes it
    easier to read and debug because you can follow information flow from
    the prototypes only, and it also stops developers who use your library
    from pulling their hair out because you are printing to streams that
    you shouldn't, not following their message conventions or corrupting
    their output completely.

    viza
     
    viza, May 7, 2008
    #2
    1. Advertising

  3. Gowtham

    Willem Guest

    viza wrote:
    ) Hi
    )
    ) On May 7, 3:14 pm, Gowtham <> wrote:
    )
    )> I had some C code written which initialized a global variable as:
    )>
    )> FILE *yyerfp = stdout;
    )> ...
    )> But, this code will also be compiled into a shared object
    )> ...
    )> What is the best way of solving this problem?
    )
    ) The correct and best way to solve this problem is to remember that
    ) library functions should not write to the standard streams.
    )
    ) Imagine that stdin, stdout and stderr are local variables within
    ) main(). Any library function that needs to write to a file should
    ) take a pointer to one as an argument. The author of main() can then
    ) pass stdout *if* they give you permission to write to it.
    )
    ) This makes your code more modular and easier to reuse, it makes it
    ) easier to read and debug because you can follow information flow from
    ) the prototypes only, and it also stops developers who use your library
    ) from pulling their hair out because you are printing to streams that
    ) you shouldn't, not following their message conventions or corrupting
    ) their output completely.

    There was a discussion recently where someone was trying all kinds of hacks
    and workarounds to capture the output from a library, because he did not
    want it to go to stdout.

    I would consider that a very good example of why your advice is good
    advice. To the OP: libraries shouldn't be using stdout, and certainly
    not hardwired.


    SaSW, Willem
    --
    Disclaimer: I am in no way responsible for any of the statements
    made in the above text. For all I know I might be
    drugged or something..
    No I'm not paranoid. You all think I'm paranoid, don't you !
    #EOT
     
    Willem, May 7, 2008
    #3
  4. In article <>,
    Willem <> wrote:

    >)> FILE *yyerfp = stdout;


    >I would consider that a very good example of why your advice is good
    >advice. To the OP: libraries shouldn't be using stdout, and certainly
    >not hardwired.


    In general I agree.

    But the fact that he's using it to initialise a variable strongly
    suggests that it is *not* hardwired, but just a default. If the user
    wasn't supposed to be able to change it, the OP could just use stdio
    instead of yyerfp.

    Assuming the OP can change the code of the library, he could
    initialise yyerfp to NULL and replace all the uses of it with

    (yyerfp ? yyerfp : stdout)

    It's a pity there isn't a standard way to get initialisation code run.

    -- Richard
    --
    :wq
     
    Richard Tobin, May 7, 2008
    #4
  5. Gowtham

    Guest

    On May 7, 8:01 pm, (Richard Tobin) wrote:
    > In article <>,
    >
    > Willem <> wrote:
    > >)> FILE *yyerfp = stdout;
    > >I would consider that a very good example of why your advice is good
    > >advice. To the OP: libraries shouldn't be using stdout, and certainly
    > >not hardwired.

    >
    > In general I agree.
    >
    > But the fact that he's using it to initialise a variable strongly
    > suggests that it is *not* hardwired, but just a default. If the user
    > wasn't supposed to be able to change it, the OP could just use stdio
    > instead of yyerfp.
    >
    > Assuming the OP can change the code of the library, he could
    > initialise yyerfp to NULL and replace all the uses of it with
    >
    > (yyerfp ? yyerfp : stdout)

    Slightly better way:

    FILE *yyerfp_;
    /* ... */
    #define yyerfp (yyerfp ? yyerfp : stdout)

    > It's a pity there isn't a standard way to get initialisation code run.

    I don't think it's that much of a problem. Well-designed code wouldn't
    use global variables. (with few exceptions such as errno)
     
    , May 7, 2008
    #5
  6. Gowtham

    Guest

    On May 7, 8:29 pm, wrote:
    > On May 7, 8:01 pm, (Richard Tobin) wrote:
    >
    > > In article <>,

    >
    > > Willem <> wrote:
    > > >)> FILE *yyerfp = stdout;
    > > >I would consider that a very good example of why your advice is good
    > > >advice. To the OP: libraries shouldn't be using stdout, and certainly
    > > >not hardwired.

    >
    > > In general I agree.

    >
    > > But the fact that he's using it to initialise a variable strongly
    > > suggests that it is *not* hardwired, but just a default. If the user
    > > wasn't supposed to be able to change it, the OP could just use stdio
    > > instead of yyerfp.

    >
    > > Assuming the OP can change the code of the library, he could
    > > initialise yyerfp to NULL and replace all the uses of it with

    >
    > > (yyerfp ? yyerfp : stdout)

    >
    > Slightly better way:
    >
    > FILE *yyerfp_;
    > /* ... */
    > #define yyerfp (yyerfp ? yyerfp : stdout)

    Sigh, what's up with all these mistakes lately...
    #define yyerfp (yyerfp_ ? yyerfp_ : stdout)

    > > It's a pity there isn't a standard way to get initialisation code run.

    >
    > I don't think it's that much of a problem. Well-designed code wouldn't
    > use global variables. (with few exceptions such as errno)
     
    , May 7, 2008
    #6
  7. In article <>,
    <> wrote:

    >> It's a pity there isn't a standard way to get initialisation code run.


    >I don't think it's that much of a problem. Well-designed code wouldn't
    >use global variables.


    You're letting a slogan override your common sense. There are many
    cases of global variables that are completely reasonable.

    For example, I want to convert between ISO Latin-5 (an 8-bit character
    set) and Unicode code points (which can be considered to have 2^16
    characters for this purpose). To do this, I have a table of 256
    entries mapping Latin-5 to Unicode, and I want to build the reverse
    table at start-up. These two global variables, latin_5_to_unicode and
    unicode_to_latin_5, have no objectionable properties.

    > (with few exceptions such as errno)


    Not a reasonable example at all. It was adequate 20 years ago, but
    today is a fine example of the problems with global variables.

    -- Richard
    --
    :wq
     
    Richard Tobin, May 7, 2008
    #7
  8. (Richard Tobin) writes:
    > In article <>,
    > <> wrote:
    >
    >>> It's a pity there isn't a standard way to get initialisation code run.

    >
    >>I don't think it's that much of a problem. Well-designed code wouldn't
    >>use global variables.

    >
    > You're letting a slogan override your common sense. There are many
    > cases of global variables that are completely reasonable.
    >
    > For example, I want to convert between ISO Latin-5 (an 8-bit character
    > set) and Unicode code points (which can be considered to have 2^16
    > characters for this purpose). To do this, I have a table of 256
    > entries mapping Latin-5 to Unicode, and I want to build the reverse
    > table at start-up. These two global variables, latin_5_to_unicode and
    > unicode_to_latin_5, have no objectionable properties.

    [...]

    Without resurrecting the unresolved argument over the definition of
    "variable" I'll note that your global objects latin_5_to_unicode and
    unicode_to_latin_5 presumably do not vary once they've been
    initialized. Global objects whose values are never modified during
    program execution are less problematic than global objects whose
    values can vary over time. ("Global" here refers to file scope and
    static duration, more or less.)

    --
    Keith Thompson (The_Other_Keith) <>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, May 7, 2008
    #8
  9. Gowtham

    Guest

    On May 7, 10:21 pm, (Richard Tobin) wrote:
    > In article <>,
    >
    > <> wrote:
    > >> It's a pity there isn't a standard way to get initialisation code run.

    > >I don't think it's that much of a problem. Well-designed code wouldn't
    > >use global variables.

    >
    > You're letting a slogan override your common sense. There are many
    > cases of global variables that are completely reasonable.
    >
    > For example, I want to convert between ISO Latin-5 (an 8-bit character
    > set) and Unicode code points (which can be considered to have 2^16
    > characters for this purpose). To do this, I have a table of 256
    > entries mapping Latin-5 to Unicode, and I want to build the reverse
    > table at start-up. These two global variables, latin_5_to_unicode and
    > unicode_to_latin_5, have no objectionable properties.

    Ah, indeed. Another example would be a table for all the is*()
    functions in <ctype.h>, in a C lib implementation.
    I just try to avoid global variables, because they can lead to a bad
    design, when there's a better option available.
    > > (with few exceptions such as errno)

    >
    > Not a reasonable example at all. It was adequate 20 years ago, but
    > today is a fine example of the problems with global variables.

    OK, you are right. I can see what you mean, one example would be with
    threads I suppose.
    I have not read much on alternative solutions to errno in C, so is
    there a better solution?
    Returning the error code is not possible (like pthreads) and an extra
    parameter to every function that can fail would be quite annoying.
     
    , May 7, 2008
    #9
  10. Gowtham wrote:
    > Hi,
    >
    > I had some C code written which initialized a global variable as:
    >
    > FILE *yyerfp = stdout;


    In C, stdin, stdout and stderr are macros. They needn't be
    constant expressions.

    > This used to work fine in older versions of gcc. Now, when I
    > tried to compile this code (with gcc 3.2.3),
    > I got errors like:
    >
    > ../Include/Message.h:42: initializer element is not constant


    That is your error, not glibc's.

    > I looked around the www and found that stdin/stdout/stderr
    > are *not* made const in the newer versions of gcc.


    They don't need to be.

    > As a work-around, I thought of this:
    >
    > FILE *yyerfp; // Uninitialized global


    Actually, it's zero initialised (to a null pointer).

    > // Initialize it in a separate function
    > void initializeGlobals( void )
    > {
    > yyerfp = stdout;
    > }
    >
    > int main( ... )
    > {
    > // Initialize the global before doing anything else
    > initializeGlobals();
    > ...
    > // Do other things
    > }
    >
    > But, this code will also be compiled into a shared object,
    > dynamically loadable from other languages such as perl etc.
    > and I do not want to change the API interface there.


    Fine, but in a sense, it's your interface that is a problem.

    > If I follow this approach, I also have to add the
    > initializeGlobals() call in every perl program which uses
    > this library.


    Replace it with a macro/function like...

    #define YYERFP \
    (yyerfp ? yyerfp : (yyerfp = stdout))

    int library_foo()
    {
    FILE *fp = YYERFP;
    ...
    }

    <OT> The other choice of course is C++ </OT>

    > What is the best way of solving this problem?


    Don't make libraries dependant on non-zero initialisation of
    static variables.

    --
    Peter
     
    Peter Nilsson, May 7, 2008
    #10
  11. In article <>,
    <> wrote:

    >I have not read much on alternative solutions to errno in C, so is
    >there a better solution?
    >Returning the error code is not possible (like pthreads) and an extra
    >parameter to every function that can fail would be quite annoying.


    The C standard recognises the problems with errno and doesn't require
    it to be an identifier. It just has to be a macro that produces a
    modifiable lvalue. So a threaded implementation can do something
    like

    #define errno (*__thread_errno())

    where __thread_errno() returns a pointer to a per-thread variable.

    -- Richard
    --
    :wq
     
    Richard Tobin, May 7, 2008
    #11
  12. Gowtham

    Ben Pfaff Guest

    (Richard Tobin) writes:

    > The C standard recognises the problems with errno and doesn't require
    > it to be an identifier.


    It's definitely an identifier. However, it might not be the name
    of a variable with external linkage.
    --
    "I hope, some day, to learn to read.
    It seems to be even harder than writing."
    --Richard Heathfield
     
    Ben Pfaff, May 7, 2008
    #12
  13. In article <>,
    Ben Pfaff <> wrote:

    >> The C standard recognises the problems with errno and doesn't require
    >> it to be an identifier.


    >It's definitely an identifier.


    Obviously "errno" is an identifier. I should have said that it's a
    macro that doesn't have to expand to an identifier.

    >However, it might not be the name of a variable with external linkage.


    It might not expand to the name of a variable at all.

    -- Richard
    --
    :wq
     
    Richard Tobin, May 7, 2008
    #13
  14. Gowtham

    Guest

    In article <>,
    Ben Pfaff <> wrote:
    > (Richard Tobin) writes:
    >
    >> The C standard recognises the problems with errno and doesn't require
    >> it to be an identifier.

    >
    >It's definitely an identifier. However, it might not be the name
    >of a variable with external linkage.


    errno is explicitly allowed to be a macro (n869 7.5#2).
    A brief look through the definitions in n869 indicates that a macro
    name is indeed covered under the standardese use of "identifier", but
    it seems that referring to a macro as an identifier in informal use is
    gratuitiously confusing, especially when what the macro expands to need
    not be an identifier.


    dave

    --
    Dave Vandervies dj3vande at eskimo dot com
    I would definitely not be sure that it does what the programmer
    intended, even if the programmer was me.
    --Christian Bau in comp.lang.c
     
    , May 7, 2008
    #14
  15. Gowtham

    Ben Pfaff Guest

    (Richard Tobin) writes:

    > In article <>,
    > Ben Pfaff <> wrote:
    >
    >>> The C standard recognises the problems with errno and doesn't require
    >>> it to be an identifier.

    >
    >>It's definitely an identifier.

    >
    > Obviously "errno" is an identifier. I should have said that it's a
    > macro that doesn't have to expand to an identifier.
    >
    >>However, it might not be the name of a variable with external linkage.

    >
    > It might not expand to the name of a variable at all.


    Right. That's one way that it might not be the name of a
    variable with external linkage.
    --
    char a[]="\n .CJacehknorstu";int putchar(int);int main(void){unsigned long b[]
    ={0x67dffdff,0x9aa9aa6a,0xa77ffda9,0x7da6aa6a,0xa67f6aaa,0xaa9aa9f6,0x11f6},*p
    =b,i=24;for(;p+=!*p;*p/=4)switch(0[p]&3)case 0:{return 0;for(p--;i--;i--)case+
    2:{i++;if(i)break;else default:continue;if(0)case 1:putchar(a[i&15]);break;}}}
     
    Ben Pfaff, May 7, 2008
    #15
  16. Gowtham

    Flash Gordon Guest

    Richard Tobin wrote, On 07/05/08 23:29:
    > In article <>,
    > <> wrote:
    >
    >> I have not read much on alternative solutions to errno in C, so is
    >> there a better solution?
    >> Returning the error code is not possible (like pthreads) and an extra
    >> parameter to every function that can fail would be quite annoying.

    >
    > The C standard recognises the problems with errno and doesn't require
    > it to be an identifier. It just has to be a macro that produces a
    > modifiable lvalue. So a threaded implementation can do something
    > like
    >
    > #define errno (*__thread_errno())
    >
    > where __thread_errno() returns a pointer to a per-thread variable.


    One real example of this is current versions of glibc where after a bit
    of digging I get
    # define errno (* __errno_location ())
    --
    Flash Gordon
     
    Flash Gordon, May 8, 2008
    #16
  17. > Assuming the OP can change the code of the library, he could
    > initialise yyerfp to NULL and replace all the uses of it with
    >
    > (yyerfp ? yyerfp : stdout)
    >
    > It's a pity there isn't a standard way to get initialisation code run.
    >
    > -- Richard


    I'd mention here a few more poins:
    - <OFF>The OP want's to initialise his shared library
    (although he could avoid it with a different design). [he can
    be she]
    This is usally possible on a decent operating system by
    defining
    a function with a magic name.
    </OFF>
    - Global objects are not quite unusual animals (especially if they are
    constant)
    and one can design them using e.g. a variant of the singleton
    pattern.
    In C that would be to define a pointer-to-function, and one can
    indeed initialise that
    to an other function. In this case:

    FILE *yyerrf_default() { return stdout; }
    static FILE *yyerrf_ptr;
    FILE *yyerrf_user() { return yyerrf_ptr; }
    FILE *(*yyerrf)()=yyerrf_default;
    void yyerrf_set(FILE *F) { yyerrf_ptr=F; yyerrf=yyerrf_user; }
    #define yyerrf yyerrf() // protected // don't yell // is legal in
    c99
    #define yyerrf_ptr // protected

    (This is a slightly overcomplicated singleton, but of some
    unjustified reasons I avoid conditionals.)

    Szabolcs
     
    Szabolcs Borsanyi, May 9, 2008
    #17
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Todd Nathan

    Error: "initializer element is not constant"

    Todd Nathan, Jul 30, 2003, in forum: C Programming
    Replies:
    2
    Views:
    19,375
    Kevin Easton
    Jul 30, 2003
  2. Levi Campbell
    Replies:
    3
    Views:
    417
    Flash Gordon
    Feb 11, 2006
  3. Replies:
    3
    Views:
    635
    Wade Ward
    Oct 21, 2007
  4. TheFlyingDutchman

    Tiny C error - initializer element is not constant

    TheFlyingDutchman, Jan 25, 2011, in forum: C Programming
    Replies:
    4
    Views:
    984
    TheFlyingDutchman
    Jan 25, 2011
  5. Bart Vandewoestyne

    error: initializer element is not constant

    Bart Vandewoestyne, Oct 3, 2012, in forum: C Programming
    Replies:
    5
    Views:
    594
    Nobody
    Oct 4, 2012
Loading...

Share This Page