Handling 'initializer element not constant' error

G

Gowtham

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
 
V

viza

Hi

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
 
W

Willem

viza wrote:
) Hi
)
)
)> 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
 
R

Richard Tobin

Willem said:
)> 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
 
V

vippstar

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)
 
R

Richard Tobin

It's a pity there isn't a standard way to get initialisation code run.
[/QUOTE]
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
 
K

Keith Thompson

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.[/QUOTE]
[...]

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.)
 
V

vippstar

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.
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.
 
P

Peter Nilsson

Gowtham said:
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;
...
}

What is the best way of solving this problem?

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

Richard Tobin

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
 
B

Ben Pfaff

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.
 
R

Richard Tobin

The C standard recognises the problems with errno and doesn't require
it to be an identifier.
[/QUOTE]
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
 
D

dj3vande

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
 
B

Ben Pfaff

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.[/QUOTE]

Right. That's one way that it might not be the name of a
variable with external linkage.
 
F

Flash Gordon

Richard Tobin wrote, On 07/05/08 23:29:
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 ())
 
S

Szabolcs Borsanyi

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top