Initializer element not constant

G

grid

Hi,
I am trying to populate an array of structures with values when I get
an error like :

typedefs.c:50: warning: initializer element is not computable at load time
typedefs.c:50: error: initializer element is not constant
typedefs.c:50: error: (near initialization for `rgDescInfo[3].NewValue')
typedefs.c:51: error: initializer element is not constant
typedefs.c:51: error: (near initialization for `rgDescInfo[3]')

typedef.c is being included in another .c file for compilation.

Below is the excert where it is failing.

unsigned short StatusArray[STATUS_ARRAY_SIZE];

struct tagDescInfo {
short uwDescField;
char *szDescFieldName;
int fHeader;
short fGettable;
short fSettable;
short fDefault;
unsigned long NewValue;
unsigned long DefaultVal;
short cbValue;
int size;
} rgDescInfo[] = {

1001, "SQL_DESC_COUNT", 1, 1|2|4|8, 1|4|2, 1|4|2, 1, 0,sizeof(short),(-8),

1099, "SQL_DESC_ALLOC_TYPE", 1, 1|2|4|8, 0, 1|2|4|8, 0, 1,
sizeof(short), (-8),

20, "SQL_DESC_ARRAY_SIZE", 1, 1|4, 1|4, 1|4, 5, 1, sizeof(short),(-5),

21, "SQL_DESC_ARRAY_STATUS_PTR", 1, 1|2|4|8, 1|2|4|8, 1|2|4|8,
(unsigned int)(StatusArray), 0L, sizeof(void *), (-4)
};

Just for information, I am using gcc-3.4.2 and the -m64 ( 64 bit
executable) option.This works fine when I compile for 32 bit but gives
the above errors while it compiles for 64 bit.

Can someone comment if this sounds like a problem from the C language
perspective.If not then I will take it to the gcc mailing lists.

TIA
 
E

Emmanuel Delahaye

grid wrote on 30/07/05 :
typedefs.c:50: warning: initializer element is not computable at load time
typedefs.c:50: error: initializer element is not constant
typedefs.c:50: error: (near initialization for `rgDescInfo[3].NewValue')
typedefs.c:51: error: initializer element is not constant
typedefs.c:51: error: (near initialization for `rgDescInfo[3]')

typedef.c is being included in another .c file for compilation.

You sould post a complable snippet that displays the problem. This is
compiling fine:

#define STATUS_ARRAY_SIZE 3

int main (void)
{
unsigned short StatusArray[STATUS_ARRAY_SIZE];

struct tagDescInfo
{
short uwDescField;
char *szDescFieldName;
int fHeader;
short fGettable;
short fSettable;
short fDefault;
unsigned long NewValue;
unsigned long DefaultVal;
short cbValue;
int size;
}
rgDescInfo[] =
{

{
1001,
"SQL_DESC_COUNT",
1,
1 | 2 | 4 | 8,
1 | 4 | 2,
1 | 4 | 2,
1,
0,
sizeof (short),
(-8),
}
,
{
1099,
"SQL_DESC_ALLOC_TYPE",
1,
1 | 2 | 4 | 8,
0,
1 | 2 | 4 | 8,
0,
1,
sizeof (short),
(-8),
}
,
{
20,
"SQL_DESC_ARRAY_SIZE",
1,
1 | 4,
1 | 4,
1 | 4,
5,
1,
sizeof (short), (-5),
}
,
{
21,
"SQL_DESC_ARRAY_STATUS_PTR",
1,
1 | 2 | 4 | 8,
1 | 2 | 4 | 8,
1 | 2 | 4 | 8,
(unsigned int) (StatusArray),
0L,
sizeof (void *),
(-4)
}
,
};

return 0;
}

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

I once asked an expert COBOL programmer, how to
declare local variables in COBOL, the reply was:
"what is a local variable?"
 
E

Emmanuel Delahaye

(supersedes <[email protected]>)

grid wrote on 30/07/05 :
typedefs.c:50: warning: initializer element is not computable at load time
typedefs.c:50: error: initializer element is not constant
typedefs.c:50: error: (near initialization for `rgDescInfo[3].NewValue')
typedefs.c:51: error: initializer element is not constant
typedefs.c:51: error: (near initialization for `rgDescInfo[3]')

typedef.c is being included in another .c file for compilation.

You should post a compilable snippet that displays the problem. This is
compiling finely:

#define STATUS_ARRAY_SIZE 3

int main (void)
{
unsigned short StatusArray[STATUS_ARRAY_SIZE];

struct tagDescInfo
{
short uwDescField;
char *szDescFieldName;
int fHeader;
short fGettable;
short fSettable;
short fDefault;
unsigned long NewValue;
unsigned long DefaultVal;
short cbValue;
int size;
}
rgDescInfo[] =
{

{
1001,
"SQL_DESC_COUNT",
1,
1 | 2 | 4 | 8,
1 | 4 | 2,
1 | 4 | 2,
1,
0,
sizeof (short),
(-8),
}
,
{
1099,
"SQL_DESC_ALLOC_TYPE",
1,
1 | 2 | 4 | 8,
0,
1 | 2 | 4 | 8,
0,
1,
sizeof (short),
(-8),
}
,
{
20,
"SQL_DESC_ARRAY_SIZE",
1,
1 | 4,
1 | 4,
1 | 4,
5,
1,
sizeof (short), (-5),
}
,
{
21,
"SQL_DESC_ARRAY_STATUS_PTR",
1,
1 | 2 | 4 | 8,
1 | 2 | 4 | 8,
1 | 2 | 4 | 8,
(unsigned int) (StatusArray),
0L,
sizeof (void *),
(-4)
}
,
};

return 0;
}


--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Clearly your code does not meet the original spec."
"You are sentenced to 30 lashes with a wet noodle."
-- Jerry Coffin in a.l.c.c++
 
C

Carlos

grid wrote:
[...]
typedefs.c:50: error: initializer element is not constant [...]
unsigned short StatusArray[STATUS_ARRAY_SIZE];

struct tagDescInfo {
short uwDescField;
char *szDescFieldName;
int fHeader;
short fGettable;
short fSettable;
short fDefault;
unsigned long NewValue;
unsigned long DefaultVal;
short cbValue;
int size;
} rgDescInfo[] = { [...]
21, "SQL_DESC_ARRAY_STATUS_PTR", 1, 1|2|4|8, 1|2|4|8, 1|2|4|8,
(unsigned int)(StatusArray), 0L, sizeof(void *), (-4)
};

I guess it is because of the different sizes of pointer and unsigned
int. This also doesn't work:

$ cat arr.c
char a[4];

unsigned char c = (unsigned char)a;

int main (void)
{
return 0;
}
$ gcc arr.c
arr.c:3: error: initializer element is not constant

I think, the compiler tries to shift 'a' to give 'c' a value, but it
doesn't know the value of 'a'. If they were the same size, I suppose it
would let the linker fill the value. I don't know if that type of
casting is legal C, though. I didn't find anything about it in the FAQ
<ot>(but I did found the answer to my previous question there,
ahem...)</ot>.

Maybe you could try using a union for 'NewValue'...

Good luck.
 
J

Jack Klein

Hi,
I am trying to populate an array of structures with values when I get
an error like :

typedefs.c:50: warning: initializer element is not computable at load time
typedefs.c:50: error: initializer element is not constant
typedefs.c:50: error: (near initialization for `rgDescInfo[3].NewValue')
typedefs.c:51: error: initializer element is not constant
typedefs.c:51: error: (near initialization for `rgDescInfo[3]')

typedef.c is being included in another .c file for compilation.

Below is the excert where it is failing.

unsigned short StatusArray[STATUS_ARRAY_SIZE];

struct tagDescInfo {
short uwDescField;
char *szDescFieldName;
int fHeader;
short fGettable;
short fSettable;
short fDefault;
unsigned long NewValue;
unsigned long DefaultVal;
short cbValue;
int size;
} rgDescInfo[] = {

1001, "SQL_DESC_COUNT", 1, 1|2|4|8, 1|4|2, 1|4|2, 1, 0,sizeof(short),(-8),

1099, "SQL_DESC_ALLOC_TYPE", 1, 1|2|4|8, 0, 1|2|4|8, 0, 1,
sizeof(short), (-8),

20, "SQL_DESC_ARRAY_SIZE", 1, 1|4, 1|4, 1|4, 5, 1, sizeof(short),(-5),

21, "SQL_DESC_ARRAY_STATUS_PTR", 1, 1|2|4|8, 1|2|4|8, 1|2|4|8,
(unsigned int)(StatusArray), 0L, sizeof(void *), (-4)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
};

Just for information, I am using gcc-3.4.2 and the -m64 ( 64 bit
executable) option.This works fine when I compile for 32 bit but gives
the above errors while it compiles for 64 bit.

Can someone comment if this sounds like a problem from the C language
perspective.If not then I will take it to the gcc mailing lists.

TIA

I assume the compiler is objecting to the expression above that I
highlighted. I am a little leery of the cast to unsigned int to
initialize a value defined as unsigned long, and in general casting a
pointer to unsigned int on a 64-bit implementation. Are you sure
pointer, int, and long are all the same size, or is int narrower?

I also have one question and one observation:

Is the definition of 'StatusArray' at file or block scope? If it is
not at file scope, or defined static, you can't use its address in an
aggregate initializer.

Even if it is static, my reading of the current C standard allows, but
does not require, the compiler to accept the code.

Assuming that 'rgDescInfo' itself is defined at file scope and so has
static storage duration, all initializers must be constant
expressions. Section 6.6 of the C standard defines constant
expressions, here are the relevant paragraphs:

========
6 An integer constant expression96) shall have integer type and shall
only have operands that are integer constants, enumeration constants,
character constants, sizeof expressions whose results are integer
constants, and floating constants that are the immediate operands of
casts. Cast operators in an integer constant expression shall only
convert arithmetic types to integer types, except as part of an
operand to the sizeof operator.

7 More latitude is permitted for constant expressions in initializers.
Such a constant expression shall be, or evaluate to, one of the
following:
— an arithmetic constant expression,
— a null pointer constant,
— an address constant, or
— an address constant for an object type plus or minus an integer
constant expression.

8 An arithmetic constant expression shall have arithmetic type and
shall only have operands that are integer constants, floating
constants, enumeration constants, character constants, and sizeof
expressions. Cast operators in an arithmetic constant expression
shall only convert arithmetic types to arithmetic types, except as
part of an operand to a sizeof operator whose result is an integer
constant.

9 An address constant is a null pointer, a pointer to an lvalue
designating an object of static storage duration, or a pointer to a
function designator; it shall be created explicitly using
the unary & operator or an integer constant cast to pointer type, or
implicitly by the use of an expression of array or function type. The
array-subscript [] and member-access . and -> operators, the address &
and indirection * unary operators, and pointer casts may be used in
the creation of an address constant, but the value of an object shall
not be accessed by use of these operators.

10 An implementation may accept other forms of constant expressions.
========

An initializer for an integer type, in this case 'unsigned long
NewValue', must be an 'arithmetic constant expression', which in turn
is based on 'integer constant expression'. The final sentence of
paragraph 6 states explicitly: "Cast operators in an integer constant
expression shall only convert arithmetic types to integer types". The
final sentence of paragraph repeats the same thing in the larger
context: "Cast operators in an arithmetic constant expression shall
only convert arithmetic types to arithmetic types".

So the cast of a address to unsigned int, or any other integer type,
even if the address belongs to an object with static storage duration
(paragraph 9), does not qualify as an 'integer constant expression',
nor does it qualify as an 'address constant expression'. The value of
a pointer, or an address in general, is not an 'arithmetic type'.

So the compiler is not required to accept this as an initializer for a
member of your array of structures. Paragraph 10 allows an
implementation to accept initializers that don't meet the rules
defined above. So your earlier version of gcc accepting them is a
case of either unspecified or implementation-defined behavior.
 
J

Jack Klein

grid wrote on 30/07/05 :
typedefs.c:50: warning: initializer element is not computable at load time
typedefs.c:50: error: initializer element is not constant
typedefs.c:50: error: (near initialization for `rgDescInfo[3].NewValue')
typedefs.c:51: error: initializer element is not constant
typedefs.c:51: error: (near initialization for `rgDescInfo[3]')

typedef.c is being included in another .c file for compilation.

You sould post a complable snippet that displays the problem. This is
compiling fine:

#define STATUS_ARRAY_SIZE 3

int main (void)
{
unsigned short StatusArray[STATUS_ARRAY_SIZE];

struct tagDescInfo
{
short uwDescField;
char *szDescFieldName;
int fHeader;
short fGettable;
short fSettable;
short fDefault;
unsigned long NewValue;
unsigned long DefaultVal;
short cbValue;
int size;
}
rgDescInfo[] =
{

{
1001,
"SQL_DESC_COUNT",
1,
1 | 2 | 4 | 8,
1 | 4 | 2,
1 | 4 | 2,
1,
0,
sizeof (short),
(-8),
}
,
{
1099,
"SQL_DESC_ALLOC_TYPE",
1,
1 | 2 | 4 | 8,
0,
1 | 2 | 4 | 8,
0,
1,
sizeof (short),
(-8),
}
,
{
20,
"SQL_DESC_ARRAY_SIZE",
1,
1 | 4,
1 | 4,
1 | 4,
5,
1,
sizeof (short), (-5),
}
,
{
21,
"SQL_DESC_ARRAY_STATUS_PTR",
1,
1 | 2 | 4 | 8,
1 | 2 | 4 | 8,
1 | 2 | 4 | 8,
(unsigned int) (StatusArray),
0L,
sizeof (void *),
(-4)
}
,
};

return 0;
}

The OP's post implies, although he does not explicitly state, that the
'rgDescInfo' is defined at file scope, and so has static storage
duration. The rules for initializers of static objects are different,
and more restrictive, than those for automatic objects, like you used
in your example.

See my reply to the OP about why a compiler may, but is not required
to, accept '(unsigned int) (StatusArray)' as the initializer for an
object with static storage duration.
 
G

grid

The OP's post implies, although he does not explicitly state, that the
'rgDescInfo' is defined at file scope, and so has static storage
duration. The rules for initializers of static objects are different,
and more restrictive, than those for automatic objects, like you used
in your example.

Jack,its all described at file scope.
The following program just produces the error which I am getting.I am
using gcc-3.4.2 with the -m64 option.Without the -m64 option it compiles
just fine.I suppose its something related to the StatusArray address
being 64 bits.

#define STATUS_ARRAY_SIZE 3

unsigned short StatusArray[STATUS_ARRAY_SIZE];

struct tagDescInfo
{
short uwDescField;
char *szDescFieldName;
int fHeader;
short fGettable;
short fSettable;
short fDefault;
unsigned int NewValue;
unsigned long DefaultVal;
short cbValue;
int size;
}
rgDescInfo[] =
{

{
1001,
"SQL_DESC_COUNT",
1,
1 | 2 | 4 | 8,
1 | 4 | 2,
1 | 4 | 2,
1,
0,
sizeof (short),
(-8),
}
,
{
1099,
"SQL_DESC_ALLOC_TYPE",
1,
1 | 2 | 4 | 8,
0,
1 | 2 | 4 | 8,
0,
1,
sizeof (short),
(-8),
}
,
{
20,
"SQL_DESC_ARRAY_SIZE",
1,
1 | 4,
1 | 4,
1 | 4,
5,
1,
sizeof (short), (-5),
}
,
{
21,
"SQL_DESC_ARRAY_STATUS_PTR",
1,
1 | 2 | 4 | 8,
1 | 2 | 4 | 8,
1 | 2 | 4 | 8,
(unsigned int) (StatusArray),
0L,
sizeof (void *),
(-4)
}
,
};

int main (void)
{

return 0;
}


TIA
~
 
J

Jack Klein

Jack,its all described at file scope.
The following program just produces the error which I am getting.I am
using gcc-3.4.2 with the -m64 option.Without the -m64 option it compiles
just fine.I suppose its something related to the StatusArray address
being 64 bits.

The fact that the address is 64 bits and you are casting it to
unsigned int, which I assume is 32 bits, would cause a nasty run-time
problem, since first if any of the upper 32 bits of the pointer are 1,
the cast itself produces undefined behavior, and second, if you later
try to convert the value back into a pointer, you will have a bad
pointer.

In your original post you asked, and I quote:
Can someone comment if this sounds like a problem from the C language
perspective.If not then I will take it to the gcc mailing lists.

And I tried to answer your question in terms of the C standard. I
will try again and be less subtle:

#define STATUS_ARRAY_SIZE 3

unsigned short StatusArray[STATUS_ARRAY_SIZE];

struct tagDescInfo
{
short uwDescField;
char *szDescFieldName;
int fHeader;
short fGettable;
short fSettable;
short fDefault;
unsigned int NewValue;

[snip]
{
21,
"SQL_DESC_ARRAY_STATUS_PTR",
1,
1 | 2 | 4 | 8,
1 | 2 | 4 | 8,
1 | 2 | 4 | 8,
(unsigned int) (StatusArray),

[snip]

You have a structure member defined as 'unsigned int NewValue', and in
an object of this type with static storage duration you are trying to
initialize it with the expression '(unsigned int) (StatusArray)',
which is a cast of the pointer to the first element of an array with
static storage duration.

The C standard says that '(unsigned int) (StatusArray)' is ---NOT--- a
valid initializer for any sort of integer object with static storage
duration, whether it is a member of a structure or not.

So your compiler, with one set of options, is quite free to reject
this and is conforming to the C standard when it does so.

But the same part of the C standard that says this is ---NOT--- a
valid initializer also says that an implementation ---MAY--- accept
other forms of initializers that are not on the list.

So you are in a gray area of the language. The standard allows a
compiler to accept or reject the code. It is up to the compiler. It
is a QOI (Quality Of Implementation) issue.

If you think your compiler should always accept this code, or if you
think your compiler should always reject this code, or even if you
think your compiler should always treat this code the same way, no
matter which choice they make, then you need to talk to the gcc
maintainers.

There is absolutely no C language issue here, because both behaviors
are allowed by the standard.

But that still leaves the issue of a serious bug in the program logic,
if you get the 64-bit compiler to accept the initialization.

The code is trying to initialize a 32-bit unsigned integer with the
value of a 64-bit pointer. That is undefined behavior, but the most
likely result is that the unsigned int will discard the upper 32 bits
of the pointer and keep the lower 32 bits.

Presumably, somewhere in the program, other code will try to convert
the unsigned int back into a pointer, and dereference the pointer.
Most likely the pointer value will not be correct and undefined
behavior will result. A seg fault will be the luckiest result you
could hope for.

This is not the first time when there has been a large code base that
could assume pointers and ints were the same size, and work by
accident. This is also not the first time when a lot of that code is
broken by a change to the runtime environment, in this case pointers
becoming 64 bits while ints stay 32 bits.
 
J

Jasen Betts

Hi,
I am trying to populate an array of structures with values when I get
an error like :

typedefs.c:50: warning: initializer element is not computable at load time
typedefs.c:50: error: initializer element is not constant
typedefs.c:50: error: (near initialization for `rgDescInfo[3].NewValue')
typedefs.c:51: error: initializer element is not constant
typedefs.c:51: error: (near initialization for `rgDescInfo[3]')

typedef.c is being included in another .c file for compilation.

Below is the excert where it is failing.

unsigned short StatusArray[STATUS_ARRAY_SIZE];

struct tagDescInfo {
short uwDescField;
char *szDescFieldName;
int fHeader;
short fGettable;
short fSettable;
short fDefault;
unsigned long NewValue;
unsigned long DefaultVal;
short cbValue;
int size;
} rgDescInfo[] = {

1001, "SQL_DESC_COUNT", 1, 1|2|4|8, 1|4|2, 1|4|2, 1, 0,sizeof(short),(-8),

1099, "SQL_DESC_ALLOC_TYPE", 1, 1|2|4|8, 0, 1|2|4|8, 0, 1,
sizeof(short), (-8),

20, "SQL_DESC_ARRAY_SIZE", 1, 1|4, 1|4, 1|4, 5, 1, sizeof(short),(-5),

21, "SQL_DESC_ARRAY_STATUS_PTR", 1, 1|2|4|8, 1|2|4|8, 1|2|4|8,
(unsigned int)(StatusArray), 0L, sizeof(void *), (-4)
};

Just for information, I am using gcc-3.4.2 and the -m64 ( 64 bit
executable) option.This works fine when I compile for 32 bit but gives
the above errors while it compiles for 64 bit.

Can someone comment if this sounds like a problem from the C language
perspective.If not then I will take it to the gcc mailing lists.

other than the fact that you're casting the address of StatusArray to
unsigned short (whatever that is on a 64 bit platform) and then storing
it in an unsigned long it looks OK language wise....
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top