reporting typedef errors automatically

  • Thread starter Jens Thoms Toerring
  • Start date
J

Jens Thoms Toerring

Roman Mashak said:
I came across this method of checking the sizes:
static union
{
char int8_t_incorrect[sizeof( int8_t) == 1];
char uint8_t_incorrect[sizeof( uint8_t) == 1];
char int16_t_incorrect[sizeof( int16_t) == 2];
char uint16_t_incorrect[sizeof(uint16_t) == 2];
char int32_t_incorrect[sizeof( int32_t) == 4];
char uint32_t_incorrect[sizeof(uint32_t) == 4];

It was recommended to use this declaration in order to let compiler "report
typedef errors automatically". I'm not sure I clearly understand what the
above statement does. It's my understanding that if intN_t/uintN_t types
exist on a platfrom, 'sizeof' operator returns a proper size of them.... and
then what?

I guess it's meant to provoke the compiler to emit an error
message (or at least a warning) in the case that int8_ta and
uint8_t don't have a size of 1, int8_t/uint8_t don't have a
size of 2 etc. since in that case e.g. 'sizeof( int8_t ) == 1'
woukd be false and thus result in the value 0. And then you
would try to create an array of length 0 which isn't legal.

I don't know if this is a good idea, I guess I would instead
use something that tests if CHAR_BITS is 8 since that seems
to be what all that boils down to.

Regards, Jens
 
J

Jens Thoms Toerring

Jens Thoms Toerring said:
I guess it's meant to provoke the compiler to emit an error
message (or at least a warning) in the case that int8_ta and
uint8_t don't have a size of 1, int8_t/uint8_t don't have a
size of 2 etc.

Sorry, make that "int16_t/uint16_t don't have a size of 2"...

Regards, Jens
 
H

Harald van Dijk

Hello,

I came across this method of checking the sizes:

static union
{
char int8_t_incorrect[sizeof( int8_t) == 1];
char uint8_t_incorrect[sizeof( uint8_t) == 1];
[...]
};

It was recommended to use this declaration in order to let compiler
"report typedef errors automatically". I'm not sure I clearly understand
what the above statement does. It's my understanding that if
intN_t/uintN_t types exist on a platfrom, 'sizeof' operator returns a
proper size of them.... and then what?

The == operator evaluates to 0 if its operands compare unequal, and to 1
if they compare equal. Normally, this result is used as a boolean value,
but it is a plain old int. (1 == 1) == 1. (1 == 2) == 0. So an array of
length (sizeof(int8_t) == 1) is an array of length 1, if
sizeof(int8_t) == 1, or else an array of length 0. When you define an
array of length 0 the compiler will let you know you're doing something
wrong. So when sizeof(int8_t) != 1, the compiler will complain.

Not that sizeof(int8_t) could possibly be anything other than 1. And when
int8_t and int16_t both exist, sizeof(int16_t) cannot possibly be anything
other than 2, and when int8_t and int32_t both exist, sizeof(int32_t)
cannot possibly be anything other than 4. So the checks are fairly
pointless in this case; you could just as well simply make sure the types
exist, by using them. But the idea can be applied meaningfully to other
checks.
 
V

vippstar

Hello,

I came across this method of checking the sizes:

static union
{
char int8_t_incorrect[sizeof( int8_t) == 1];
char uint8_t_incorrect[sizeof( uint8_t) == 1];

char int16_t_incorrect[sizeof( int16_t) == 2];
char uint16_t_incorrect[sizeof(uint16_t) == 2];

char int32_t_incorrect[sizeof( int32_t) == 4];
char uint32_t_incorrect[sizeof(uint32_t) == 4];

};

It was recommended to use this declaration in order to let compiler "report
typedef errors automatically". I'm not sure I clearly understand what the
above statement does. It's my understanding that if intN_t/uintN_t types
exist on a platfrom, 'sizeof' operator returns a proper size of them.... and
then what?
If intN_t types are available, they are two's complement no padding
signed integers with exact width N.
Reference, 7.18.1.1 Exact-width integer types.
These tests are not needed.
 
J

Jens Thoms Toerring

Harald van Dijk said:
Hello,

I came across this method of checking the sizes:

static union
{
char int8_t_incorrect[sizeof( int8_t) == 1];
char uint8_t_incorrect[sizeof( uint8_t) == 1];
[...]
};

It was recommended to use this declaration in order to let compiler
"report typedef errors automatically". I'm not sure I clearly understand
what the above statement does. It's my understanding that if
intN_t/uintN_t types exist on a platfrom, 'sizeof' operator returns a
proper size of them.... and then what?
The == operator evaluates to 0 if its operands compare unequal, and to 1
if they compare equal. Normally, this result is used as a boolean value,
but it is a plain old int. (1 == 1) == 1. (1 == 2) == 0. So an array of
length (sizeof(int8_t) == 1) is an array of length 1, if
sizeof(int8_t) == 1, or else an array of length 0. When you define an
array of length 0 the compiler will let you know you're doing something
wrong. So when sizeof(int8_t) != 1, the compiler will complain.
Not that sizeof(int8_t) could possibly be anything other than 1. And when
int8_t and int16_t both exist, sizeof(int16_t) cannot possibly be anything
other than 2, and when int8_t and int32_t both exist, sizeof(int32_t)
cannot possibly be anything other than 4.

But if you have e.g. a machine where CHAR_BITS is 16 wouldn't
then sizeof(int16_t) be 1 and that of sizeof(int32_t) be 2?
I have never had a chance to use such machines but it would
seem logical to me.
Regards, Jens
 
H

Harald van Dijk

And when int8_t and int16_t both exist, sizeof(int16_t) cannot possibly
be anything other than 2,
[ snip ]
But if you have e.g. a machine where CHAR_BITS is 16 wouldn't then
sizeof(int16_t) be 1
[ snip ]

Correct. However, on a machine where CHAR_BIT is anything other than 8,
int8_t cannot be defined. In other words, if int8_t exists, you already
know that CHAR_BIT is equal to 8.
 
S

Szabolcs Borsanyi

If intN_t types are available, they are two's complement no padding
signed integers with exact width N.
Reference, 7.18.1.1 Exact-width integer types.
These tests are not needed.

That's strange. 7.18.1.1 says

1 The typedef name intN_t designates a signed integer type with width N, no
padding bits, and a two's complement representation. Thus, int8_t denotes a
signed integer type with a width of exactly 8 bits.

and also:

3 These types are optional. However, if an implementation provides integer
types with widths of 8, 16, 32, or 64 bits, it shall define the corresponding
typedef names.

Does that imply that if an implementation provides 32 or 16-bit int with
one's complement representation, that it has to define int32_t, which has,
in turn, two's component representation.


Szabolcs
 
H

Harald van Dijk

That's strange. 7.18.1.1 says

1 The typedef name intN_t designates a signed integer type with width N,
no padding bits, and a two's complement representation. Thus, int8_t
denotes a signed integer type with a width of exactly 8 bits.

and also:

3 These types are optional. However, if an implementation provides
integer types with widths of 8, 16, 32, or 64 bits, it shall define the
corresponding typedef names.

Does that imply that if an implementation provides 32 or 16-bit int with
one's complement representation, that it has to define int32_t, which
has, in turn, two's component representation.

You are correct, and the text has already been changed to

3 These types are optional. However, if an implementation provides integer
types with widths of 8, 16, 32, or 64 bits, no padding bits, and (for the
signed types) that have a two's complement representation, it shall define
the corresponding typedef names.

in an attempt to address precisely that issue. It doesn't manage to do so
entirely, though: if an implementation provides a 32-bit ones' complement
signed int, and a 32-bit unsigned int, both without padding bits, then
7.18.1.1p3 requires that the implementation define uint32_t, and 7.18.1p1
states that if an implementation provides uint32_t, it must also provide
int32_t.
 
P

Peter Nilsson

Harald van D©¦k said:
...
When you define an array of length 0 the compiler
will let you know you're doing something wrong.

It is a constraint violation. Unfortunately, it's also
not an uncommon extension to allow zero sized arrays,
particularly at the end of a struct. So, I prefer
((need) ? 1 : -1) for compile time asserts.
 
H

Harald van Dijk

It is a constraint violation. Unfortunately, it's also not an uncommon
extension to allow zero sized arrays, particularly at the end of a
struct. So, I prefer ((need) ? 1 : -1) for compile time asserts.

I agree, that's a better idea. However, I seem to recall reading that
implementations exist that accept negative array length constants as well,
and that it's even safer to use bit-field widths because of that.

struct check {
int member : (... ? 1 : -1);
};

As far as standard C is concerned, all are equivalent, as all violate a
constraint if the check fails, but in practise, it's good to do whatever's
reasonably possible to ensure the diagnostic is a fatal one.
 
R

Roman Mashak

Hello,

I came across this method of checking the sizes:

static union
{
char int8_t_incorrect[sizeof( int8_t) == 1];
char uint8_t_incorrect[sizeof( uint8_t) == 1];

char int16_t_incorrect[sizeof( int16_t) == 2];
char uint16_t_incorrect[sizeof(uint16_t) == 2];

char int32_t_incorrect[sizeof( int32_t) == 4];
char uint32_t_incorrect[sizeof(uint32_t) == 4];

};

It was recommended to use this declaration in order to let compiler "report
typedef errors automatically". I'm not sure I clearly understand what the
above statement does. It's my understanding that if intN_t/uintN_t types
exist on a platfrom, 'sizeof' operator returns a proper size of them.... and
then what?

With best regards, Roman Mashak. E-mail: (e-mail address removed)
 
R

Richard Tobin

I came across this method of checking the sizes:
[/QUOTE]
This is a pretty stupid idea, and extremely non-portable. Who's
not-so-bright idea is it?

What's unportable about it? It will cause the compilation to
fail if the types are unavailable or are implemented wrongly,
which is presumably the idea.

-- Richard
 
J

Jens Thoms Toerring

Roman Mashak said:
Hello, Jens!
You wrote on 29 May 2008 20:54:28 GMT:
[skip]
JTT> I guess it's meant to provoke the compiler to emit an error
JTT> message (or at least a warning) in the case that int8_ta and
JTT> uint8_t don't have a size of 1, int8_t/uint8_t don't have a
JTT> size of 2 etc. since in that case e.g. 'sizeof( int8_t ) == 1'
JTT> woukd be false and thus result in the value 0. And then you
JTT> would try to create an array of length 0 which isn't legal.
I integrated the above code in the test example and compiled it twice with
'gcc -W -Wall -std=c99...' and 'gcc -W -Wall -std=c89...'. No error was
emmited in the second case. Should it have been?

That then probably means that on your system an int8_t/uint8_t
has a size of of 1, and int16_t/uint16_t has a size of 2 etc.
And, no it also shouldn't emit an error message for the C89
case since in order to compile it even in C99 mode you must
have included <stdint.h> (or some other header file that
automatically includes <stdint.h>)- in that header file the
types (int8_t,...) are defined. And if they are defined in
that header file and that header file exists and is included,
then they are defined regardless if you compile in C89 or
C99 mode.

After having had a look at the article you got that from it
is clearer what this is all about. Before C99 the existence
of a header file named <stdint.h> wasn't required and so all
these types weren't required to be defined. Thus some people
would do it themselves with typedefs like this

typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef short int int16_t;
typedef unsigned short int uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;

But this would break on a system where e.g. an int has only 16
and not 32 bits. So the whole thing proposed in that article was
meant as a check if the assumptions made when creating these
typedefs were correct for the machine you are compiling it on.
But if you have a <stdint.h> header file coming with your system
it's rather useless (unless you're paranoid if the implementation
you are using got it really right;-) to do these kind of checks,
they should always succeed.
Regards, Jens
 
R

Roman Mashak

Hello, Jens!
You wrote on 29 May 2008 20:54:28 GMT:

[skip]
JTT> I guess it's meant to provoke the compiler to emit an error
JTT> message (or at least a warning) in the case that int8_ta and
JTT> uint8_t don't have a size of 1, int8_t/uint8_t don't have a
JTT> size of 2 etc. since in that case e.g. 'sizeof( int8_t ) == 1'
JTT> woukd be false and thus result in the value 0. And then you
JTT> would try to create an array of length 0 which isn't legal.

I integrated the above code in the test example and compiled it twice with
'gcc -W -Wall -std=c99...' and 'gcc -W -Wall -std=c89...'. No error was
emmited in the second case. Should it have been?

JTT> I don't know if this is a good idea, I guess I would instead
JTT> use something that tests if CHAR_BITS is 8 since that seems
JTT> to be what all that boils down to.

With best regards, Roman Mashak. E-mail: (e-mail address removed)
 
R

Roman Mashak

Hello, Jack!
You wrote on Fri, 30 May 2008 21:41:48 -0500:

??>> Hello, Jack!
??>> You wrote on Thu, 29 May 2008 20:38:35 -0500:
??>>
JK>>> This is a pretty stupid idea, and extremely non-portable. Who's
JK>>> not-so-bright idea is it?
??>> http://www.oreillynet.com/pub/a/network/2003/10/07/michael_barr.html
??>>
??>> [skip]
??>> What portable way would you suggest? Checking the CHAR_BITS?

JK> The header <stdint.h> provides minimum and maximum macros for the
JK> exact width integer types, if and only if those particular types are
JK> defined.
[skip]
I got this yet, thanks though.


With best regards, Roman Mashak. E-mail: (e-mail address removed)
 

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,861
Messages
2,569,878
Members
46,088
Latest member
PSUSavanna

Latest Threads

Top