Question

I ran into a problem with some C code like this:

struct SomeType { ...details immaterial... };

static struct SomeType array[] =
{
    { ... },
    ...
    { ... },
};
enum { ARRAY_SIZE = sizeof(array) / sizeof(array[0]) };

The Unix compilers (various versions of GCC, and the compilers on AIX and HP-UX) were all quite happy with the enum. MSVC 2005 objected with error C2056: Illegal Expression. According to MSDN, this is because 'An expression was invalid because of a previous error'. This was the only error reported, which makes it slightly surprising.

However, my questions are:

  1. Is MSVC 2005 accurately interpreting the C89 standard in disallowing the enum?
  2. Are the Unix compilers being too generous in permitting this without warning?
  3. Does C99 (or C2011) make any difference?
  4. Do more recent versions of MSVC still object to the enum?

FWIW: the acceptable solution was to change the enum into:

static int const ARRAY_SIZE = sizeof(array) / sizeof(array[0]);

Deprecated options are troublesome

Michael Burr gave some extra information which is very valuable, and has allowed me to unlock the problem.

Compilable example (isomorphic with the actual problems):

static const char *names[] = { "abc", "def", "ghi" };
enum { NAMES_SIZE = sizeof(names) / sizeof(names[0]) };

static const struct stuff { const char *name; int flags; } array[] =
{
    { "abc", 1 },
    { "def", 2 },
    { "ghi", 3 },
};
enum { ARRAY_SIZE = sizeof(array) / sizeof(array[0]) };

The precise version of the MSVC (as given by cl) is:

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86

That's the version Michael says works.

And, I've found the cause of my problem. (The command lines below remove all the project-specific guff — the multitude of /D and /I options that aren't needed for the sample code.) Compiling with:

cl     /W3 /c /LD /MD /Od aaa.c

And the code above compiles OK.

cl /Zg /W3 /c /LD /MD /Od aaa.c

This generates first the warning:

cl : Command line warning D9035 : option 'Zg' has been deprecated and will be removed in a future release

I've been bitching about compilations being done with deprecated options for a year or more, but no-one from the team in charge of this sub-project has been willing to stand up and fix it, and I'm not supposed to — something that's about to change.

and then it says:

aaa.c(2) : error C2056: illegal expression
aaa.c(10) : error C2056: illegal expression

So, not only is the /Zg option deprecated but it is also the cause of the trouble in the first place. Now I've got some better ammunition to go after people with!

Thanks for the extra information, Michael.

PS: The MSDN page about /Zg says:

If you use the /Zg option and your program contains formal parameters that have struct, enum, or union type (or pointers to such types), the declaration of each struct, enum, or union type must have a tag (name).

That isn't wholly accurate. There are no formal parameters in the example fragment, and the enum values were never passed to a function. But without the tag on the enum, the error still appears with the /Zg flag.


(No; I'm not particularly attached to MSVC 2005. The group I work in simply hasn't upgraded to anything more recent yet. Mostly it doesn't affect me. There are occasions, like this, when it hurts a lot. One day, I'll work out why the other builds on Windows seem to be accepting the enum; I fear that I'll find this particular sub-product is out of line with everything else and using an older compiler than the other products use.)

This is strictly C code. The MSVC tag is a synonym for the Visual-C++ tag.

Was it helpful?

Solution

It is certainly legal in C89 (as long as the resulting array size is representable as an int).

The constraint in §3.5.2.2 on the defining value of an enumeration constant is:

The expression that defines the value of an enumeration constant shall be an integral constant expression that has a value representable as an int.

§3.4 describes integral constant expressions:

Constraints

Constant expressions shall not contain assignment, increment, decrement, function-call, or comma operators, except when they are contained within the operand of a sizeof operator.

Each constant expression shall evaluate to a constant that is in the range of representable values for its type.

Semantics

An expression that evaluates to a constant is required in several contexts. If the expression is evaluated in the translation environment, the arithmetic precision and range shall be at least as great as if the expression were being evaluated in the execution environment.

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top