typedef declares object / enum to int

M

Martin

This post asks two questions, which I've illustrated in one C source file
(see below), which clean compiles on my GNU compiler.

1. In K&R2, Section A8.9 it says "Declarations whose storage class specifier
is typedef do not declare object." When I compile and run my sample code,
the value "2" is displayed. Clearly the typedef has created the enumerators
S1, S2, and S3. This appears to contradict K&R2.

2. The program below was created to emulate a Lint diagnostic I got in a
much larger project. In that project, the equivalent line to fn(SYMBOL)
gives the warning

Converting enum '{...}' to int

which I find puzzling. Enumerators are int anyway, whereas the enumeration
has an integral value (according to K&R2, Section A4.4). A warning about an
enumerator (int) being converted to an int seems meaningless; and a warning
about the enumeration (integral type) being converted to int doesn't make
sense because it's the enumerator S3 that gets
passed to fn(). I've reproduced Lint's explanation of the warning below.

/* typedef declaration; Lint warning */
#include <stdio.h>

typedef enum { S1, S2, S3 } an_enum_t;

#define SYMBOL S3

typedef unsigned int Word;
void fn(Word w)
{
/* deliberately empty */
}

int main( void )
{

fn(SYMBOL);
printf("%i\n", SYMBOL);
return 0; /* success */
}

This is Lint's description of the warning:

641 Converting enum to int -- An enumeration type was used in a context that
required a computation such as an argument to an arithmetic operator or was
compared with an integral argument. This warning will be suppressed if you
use the integer model of enumeration (+fie) but you will lose some valuable
type-checking in doing so. An intermediate policy is to simply turn off this
warning. Assignment of int to enum will still be caught.

This warning is not issued for a tagless enum without variables. For example

enum {false,true};

This cannot be used as a separate type. PC-lint/FlexeLint recognizes this
and treats false and true as arithmetic constants.
 
B

Ben Pfaff

Martin said:
1. In K&R2, Section A8.9 it says "Declarations whose storage class specifier
is typedef do not declare object." When I compile and run my sample code,
the value "2" is displayed. Clearly the typedef has created the enumerators
S1, S2, and S3. This appears to contradict K&R2.

Enumeration values are not objects. Objects are regions of
storage, but enumeration values are just values.
2. The program below was created to emulate a Lint diagnostic I got in a
much larger project. [...]

I've never been impressed with lint diagnostics. Often they
don't make a whole lot of sense in context, as you've discovered.
 
M

Michael Mair

Martin said:
This post asks two questions, which I've illustrated in one C source file
(see below), which clean compiles on my GNU compiler.

1. In K&R2, Section A8.9 it says "Declarations whose storage class specifier
is typedef do not declare object." When I compile and run my sample code,
the value "2" is displayed. Clearly the typedef has created the enumerators
S1, S2, and S3. This appears to contradict K&R2.

Enumeration constants are exactly that: Constants.
They are not objects.
2. The program below was created to emulate a Lint diagnostic I got in a
much larger project. In that project, the equivalent line to fn(SYMBOL)
gives the warning

Converting enum '{...}' to int

which I find puzzling. Enumerators are int anyway, whereas the enumeration
has an integral value (according to K&R2, Section A4.4). A warning about an
enumerator (int) being converted to an int seems meaningless; and a warning
about the enumeration (integral type) being converted to int doesn't make
sense because it's the enumerator S3 that gets
passed to fn(). I've reproduced Lint's explanation of the warning below.

To clarify:
Every enumerated type is distinct from every other enumerated or
integer type but is compatible to either char or a signed or unsigned
integer type. IOW: While the identifier S3 gives you a constant of type
int, the underlying enumerated type is not necessarily int.


Cheers
Michael
 
E

E. Robert Tisdale

Martin said:
This post asks two questions, which I've illustrated in one C source file
(see below), which clean compiles on my GNU compiler.

1. In K&R2, Section A8.9 it says "Declarations whose storage class specifier
is typedef do not declare object." When I compile and run my sample code,
the value "2" is displayed. Clearly the typedef has created the enumerators
S1, S2, and S3. This appears to contradict K&R2.

No!
S1, S2 and S3 are *values* that an object of type an_enum_t can have.
They are *not* themselves objects.
2. The program below was created to emulate a Lint diagnostic
[that] I got in a much larger project.
In that project, the equivalent line to fn(SYMBOL) gives the warning

Converting enum '{...}' to int

which I find puzzling. Enumerators are int anyway, whereas the enumeration
has an integral value (according to K&R2, Section A4.4). A warning about an
enumerator (int) being converted to an int seems meaningless;
and a warning about the enumeration (integral type) being converted to int
doesn't make sense because it's the enumerator S3 that gets passed to fn().
I've reproduced Lint's explanation of the warning below.
> cat main.c
// typedef declaration; Lint warning
#include <stdio.h>

typedef enum { S1, S2, S3 } an_enum_t;

#define SYMBOL S3

typedef unsigned int Word;

void fn(Word w) {
// deliberately empty
}

int main(int argc, char* argv[]) {
fn(SYMBOL);
printf("%i\n", SYMBOL);
return 0; // success
}
> gcc -Wall -std=c99 -pedantic -o main main.c
> ./main
2

This is Lint's description of the warning:

641 Converting enum to int -- An enumeration type was used in a context that
required a computation such as an argument to an arithmetic operator or was
compared with an integral argument. This warning will be suppressed if you
use the integer model of enumeration (+fie) but you will lose some valuable
type-checking in doing so. An intermediate policy is to simply turn off this
warning. Assignment of int to enum will still be caught.

This warning is not issued for a tagless enum without variables. For example

enum {false,true};

This cannot be used as a separate type. PC-lint/FlexeLint recognizes this
and treats false and true as arithmetic constants.

So your complaint is that lint is nitpicking?
 
M

Martin

Ben Pfaff said:
Enumeration values are not objects. Objects are
regions of storage, but enumeration values are
just values.

"just values"? I'm not sure I understand. Surely S1, S2, and S3 are
identifiers representing integer constants.

I think I'm surprised that the program even understands what S3 is and can
print it out, because no variable of type an_enum_t has been declared.

I've never been impressed with lint diagnostics. Often they
don't make a whole lot of sense in context, as you've discovered.

I do find it puzzling. I don't really understand what Lint sees as the
problem.
 
M

Martin

Michael Mair said:
To clarify:
Every enumerated type is distinct from every other enumerated or integer
type but is compatible to either char or a signed or unsigned integer
type. IOW: While the identifier S3 gives you a constant of type
int, the underlying enumerated type is not
necessarily int.

But I'm passing the identifier S3 to function fn(), and S3 is the identifier
of an integer constant. By all means warn me I'm passing an int to a
function expecting unsigned int, but what does " Converting enum '{...}' to
int" supposed to mean?
 
B

Ben Pfaff

Martin said:
"just values"? I'm not sure I understand. Surely S1, S2, and S3 are
identifiers representing integer constants.

S1, S2, and S3 are not associated with regions of storage. When
you use one of them in your program, all you get is a value.
 
M

Michael Mair

Martin said:
But I'm passing the identifier S3 to function fn(), and S3 is the identifier
of an integer constant. By all means warn me I'm passing an int to a
function expecting unsigned int, but what does " Converting enum '{...}' to
int" supposed to mean?

The thing is that *lint is sometimes too paranoid (even if your being
paranoid does not mean they are not after you).
This is such a case.

It is not clear which type the enumerated type is compatible to,
thus lint sees this as a potentially dangerous conversion -- without
considering the fact that the semantics say this never can go wrong
as all candidate types undergo the standard integer promotions.

I would just throw this special warning away. Even if we forget for
a moment that casting to shut the compiler or lint up is evil, it
is completely pointless here. Casting a return value to void may
make sense sometimes but casting a constant of type int to int does
not.


Cheers
Michael
 
A

Alan Balmer

But I'm passing the identifier S3 to function fn(), and S3 is the identifier
of an integer constant. By all means warn me I'm passing an int to a
function expecting unsigned int, but what does " Converting enum '{...}' to
int" supposed to mean?

The enum value is not necessarily an int.

6.7.2.2 par 4:
Each enumerated type shall be compatible with char, a signed integer
type, or an unsigned integer type. The choice of type is
implementation-defined,108) but shall be capable of representing the
values of all the members of the enumeration.
 
M

Michael Mair

Alan said:
The enum value is not necessarily an int.

6.7.2.2 par 4:
Each enumerated type shall be compatible with char, a signed integer
type, or an unsigned integer type. The choice of type is
implementation-defined,108) but shall be capable of representing the
values of all the members of the enumeration.

However, par 3 states that the identifiers give us constants
of type int.

Cheers
Michael
 
C

Christian Kandeler

Martin said:
"just values"? I'm not sure I understand. Surely S1, S2, and S3 are
identifiers representing integer constants.

In that case, why don't you try to assign a new value to them?


Christian
 
C

Chris Croughton

But I'm passing the identifier S3 to function fn(), and S3 is the identifier
of an integer constant. By all means warn me I'm passing an int to a
function expecting unsigned int, but what does " Converting enum '{...}' to
int" supposed to mean?

It means that the compiler is being way over-zealous in issuing warning
(at least one of the ARM compilers is like that). Or possibly it means
that you are compiling C using a C++ compiler, where enums are a
different type from int.

I don't want warnings when converting int to unsigned int either, since
that is explicitly defined in the standard -- and would mean that saying
unsigned int fred = 1; gave a warning! It's bad enough when compilers
warn every time I convert with potential loss of precision or range
(like assigning an int to to a char), it results in loads of unnecessary
casts just to shut the compiler up.

Chris C
 
R

Richard Bos

Martin said:
"just values"? I'm not sure I understand. Surely S1, S2, and S3 are
identifiers representing integer constants.

Integer constant _values_, yes. Not integer objects. In effect, once
you've defined that enum, S1, S2 and S3 have the same status as 3, 4.5,
or 'a'.
I think I'm surprised that the program even understands what S3 is and can
print it out, because no variable of type an_enum_t has been declared.

So? Even if I have declared no variables of type char, putchar('x') will
work. S3 has a _value_. Once you've defined an an_enum_t object, you can
give that the value of S1, S2, or S3; but no matter which value the
object has, the program still recognises all those values. How else
would you initialise an an_enum_t in the first place, if you need one to
_have_ a value to be able to use that value?
I do find it puzzling. I don't really understand what Lint sees as the
problem.

In all probability neither does lint.

Richard
 

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,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top