how can i generate warnings for implicit casts that lose bits?

  • Thread starter robert bristow-johnson
  • Start date

R

robert bristow-johnson

here is a post i put out (using Google Groups) that got dropped by
google:

i am using gcc as so:
$ gcc -v
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --
infodir=/usr/share/info --enable-shared --enable-threads=posix --
enable-checking=release --with-system-zlib --enable-__cxa_atexit --
disable-libunwind-exceptions --enable-libgcj-multifile --enable-
languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --
disable-dssi --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre
--with-cpu=generic --host=i386-redhat-linux
Thread model: posix
gcc version 4.1.1 20060525 (Red Hat 4.1.1-1)

and have compiled a simple test program (FILE: hello.c):

//
// $ gcc -Wconversion -o hello hello.c
// $ hello
//

#include <stdio.h>
main()
{
unsigned long a_ulong = 0; // 32 bit
short a_short_array[128]; // 16 bit each

a_ulong = 1234567;

a_short_array[26] = a_ulong;

printf("%d, %hx, %x, %lx \n", sizeof(a_short_array),
a_short_array[26], a_short_array[26], a_ulong );
//
// printf output is:
//
// 256, d687, ffffd687, 12d687
//
}

and ran it as so:

$ gcc -Wconversion -o hello hello.c
$ hello

getting output:

256, d687, ffffd687, 12d687

now, i have confirmed that a short is 16 bits and an unsigned long is
32 bits. why does not this line of code:
a_short_array[26] = a_ulong;
generate a warning when i have the -Wconversion or -Wall flags set on
the gcc invocation line?

there is clearly a loss of bits (or a changing of value).

here is what the manual says about it:
from http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#Warning-Options
:

-Wconversion
Warn for implicit conversions that may alter a value. This
includes conversions between real and integer, like abs (x) when x is
double; conversions between signed and unsigned, like unsigned ui =
-1; and conversions to smaller types, like sqrtf (M_PI). Do not warn
for explicit casts like abs ((int) x) and ui = (unsigned) -1, or if
the value is not changed by the conversion like in abs (2.0). Warnings
about conversions between signed and unsigned integers can be disabled
by using -Wno-sign-conversion.

For C++, also warn for conversions between NULL and non-pointer
types; confusing overload resolution for user-defined conversions; and
conversions that will never use a type conversion operator:
conversions to void, the same type, a base class or a reference to
them. Warnings about conversions between signed and unsigned integers
are disabled by default in C++ unless -Wsign-conversion is explicitly
enabled.

is there some other compiler flag i need to hit? i don't get why this
doesn't generate a warning.
finally, please reply to both newsgroups as i don't hang around
comp.lang.c very much.

thank you,

r b-j
 
Ad

Advertisements

R

Randy Yates

robert bristow-johnson said:
[...]
now, i have confirmed that a short is 16 bits and an unsigned long is
32 bits.

How did you do that? Try this:

printf("size of short = %d, size of ulong = %d\n", sizeof(short), sizeof(unsigned long));

My suspicion is that they are both 32 bits (4 chars) on your machine
and that's why you're not getting a warning.

Robert, I NEVER use these data types anymore since I discovered
stdint.h defined in C99. I instead use explicit types like int16_t, uint32_t,
etc.
--
% Randy Yates % "Remember the good old 1980's, when
%% Fuquay-Varina, NC % things were so uncomplicated?"
%%% 919-577-9882 % 'Ticket To The Moon'
%%%% <[email protected]> % *Time*, Electric Light Orchestra
http://home.earthlink.net/~yatescr
 
R

Randy Yates

Randy Yates said:
robert bristow-johnson said:
[...]
now, i have confirmed that a short is 16 bits and an unsigned long is
32 bits.

How did you do that? Try this:

printf("size of short = %d, size of ulong = %d\n", sizeof(short), sizeof(unsigned long));

Doh! Sorry! I just reread your code and saw your statement verified there.

I have no freaking idea why the compiler doesn't burp. Not even with -Wall do I get
a warning on this conversion.
--
% Randy Yates % "She's sweet on Wagner-I think she'd die for Beethoven.
%% Fuquay-Varina, NC % She love the way Puccini lays down a tune, and
%%% 919-577-9882 % Verdi's always creepin' from her room."
%%%% <[email protected]> % "Rockaria", *A New World Record*, ELO
http://home.earthlink.net/~yatescr
 
V

Vladimir Vassilevsky

glen said:
Randy Yates wrote:

(snip)



This makes the assumption that sizeof returns an int, when it
often returns something else. Maybe you should also test
sizeof(sizeof(int))==sizeof(int)

This also makes the assumption that sizeof() returns size in bytes,
whereas sizeof returns the size in chars. Char may be bigger then one byte.

Vladimir Vassilevsky

DSP and Mixed Signal Design Consultant

http://www.abvolt.com
 
B

Ben Pfaff

glen herrmannsfeldt said:
This makes the assumption that sizeof returns an int, when it
often returns something else.

sizeof's result is never an int, although it can be an unsigned
int.
 
B

Ben Pfaff

Vladimir Vassilevsky said:
This also makes the assumption that sizeof() returns size in bytes,
whereas sizeof returns the size in chars. Char may be bigger then one
byte.

This statement reflects some confusion about C definitions. In
C, a char is always one byte, in that sizeof(char) is always 1.
However, the size of a byte is implementation-defined: it may be
larger than one octet (though not smaller).
 
Ad

Advertisements

K

Keith Thompson

Vladimir Vassilevsky said:
This also makes the assumption that sizeof() returns size in bytes,
whereas sizeof returns the size in chars. Char may be bigger then one
byte.

No, a "byte" is by definition the size of a char. The term "byte" may
have other meanings outside the context of C, but sizeof(char) is 1 by
definition.
 
K

Keith Thompson

glen herrmannsfeldt said:
Randy Yates wrote:
(snip)


This makes the assumption that sizeof returns an int, when it
often returns something else. Maybe you should also test
sizeof(sizeof(int))==sizeof(int)

No, just convert it before printing it:

printf("size of short = %d, size of unsigned long = %d\n",
(int)sizeof(short), (int)sizeof(unsigned long));

Or use "lu" and unsigned long if the result of sizeof might exceed
INT_MAX.

Or use "%zu" if your implementation supports it.
 
R

Richard Tobin

Ben Pfaff said:
However, the size of a byte is implementation-defined: it may be
larger than one octet (though not smaller).

How big is an octet on ternary machines?

-- Richard
 
O

Oli Charlesworth

Randy Yates wrote:

(snip)


This makes the assumption that sizeof returns an int, when it
often returns something else.

Perhaps it does, but on any realistic platform, why would this matter
if we're measuring the size of a short and a long?
 
R

Richard Tobin

sizeof(unsigned long));
This makes the assumption that sizeof returns an int, when it
often returns something else.
[/QUOTE]
Perhaps it does, but on any realistic platform, why would this matter
if we're measuring the size of a short and a long?

Because they're passed to a varargs function (printf), which will try
to access them as ints, so if they're in fact bigger than ints -
regardless of their value - things will go horribly wrong.

I don't think there is a simple reliable way to print a size_t in
general, since it could in principle be bigger than unsigned long
long, but in this case using (int)sizeof(short) would work.

-- Richard
 
Ad

Advertisements

R

Randy Yates

Vladimir Vassilevsky said:
This also makes the assumption that sizeof() returns size in bytes,
whereas sizeof returns the size in chars.

It is true that sizeof() returns the size in chars. It is also true
that in C, a char is, by definition, a byte.

However, even if you take "byte" to mean "8 bits," my statement was
not incorrect since Robert stated up front that the compiler was for
the i386, and that machine has 8-bit bytes.

I am aware of this "byte" definition since I ran into it on the TI TMS
C54x C compiler, where sizeof(int) = 1, even though an int is 16
bits. That machine's native datapath is 16 bits wide and incapable of
representing a type smaller than 16 bits.
--
% Randy Yates % "She has an IQ of 1001, she has a jumpsuit
%% Fuquay-Varina, NC % on, and she's also a telephone."
%%% 919-577-9882 %
%%%% <[email protected]> % 'Yours Truly, 2095', *Time*, ELO
http://home.earthlink.net/~yatescr
 
G

glen herrmannsfeldt

Randy Yates wrote:

(snip)
printf("size of short = %d, size of ulong = %d\n", sizeof(short), sizeof(unsigned long));

This makes the assumption that sizeof returns an int, when it
often returns something else. Maybe you should also test
sizeof(sizeof(int))==sizeof(int)

-- glen
 
R

Randy Yates

Perhaps it does, but on any realistic platform, why would this matter
if we're measuring the size of a short and a long?

Because they're passed to a varargs function (printf), which will try
to access them as ints, so if they're in fact bigger than ints -
regardless of their value - things will go horribly wrong.

I don't think there is a simple reliable way to print a size_t in
general, since it could in principle be bigger than unsigned long
long, but in this case using (int)sizeof(short) would work.[/QUOTE]

That brings up an interesting question: Doesn't this behavior depend
on the machine's endianness?

For example, consider the statement

printf("sizeof(int) = %d", sizeof(int));

and the case in which int is 16 bits and sizeof() returns 32 bits.

Is it true that a little-endian machine will print this correctly,
while a big-endian machine will not?
--
% Randy Yates % "She's sweet on Wagner-I think she'd die for Beethoven.
%% Fuquay-Varina, NC % She love the way Puccini lays down a tune, and
%%% 919-577-9882 % Verdi's always creepin' from her room."
%%%% <[email protected]> % "Rockaria", *A New World Record*, ELO
http://home.earthlink.net/~yatescr
 
R

Richard Tobin

For example, consider the statement

printf("sizeof(int) = %d", sizeof(int));

and the case in which int is 16 bits and sizeof() returns 32 bits.

Is it true that a little-endian machine will print this correctly,
while a big-endian machine will not?

For a common method of implementation, yes. If you printed two values
the second would print as zero.

But varargs implementations can be more complicated. They could use
separate arrays for arguments of different types, in which case they
would look in completely the wrong place for the argument.

They could also pass some arguments in registers, in which case it
might work regardless of endianness, or always fail.

-- Richard
 
R

Richard Heathfield

Richard Tobin said:
How big is an octet on ternary machines?

The requirement is to be able to represent at least 256 discrete values.
This can be accomplished in six trits, the relevant trit pattern being
100110.
 
Ad

Advertisements

R

Richard Tobin

How big is an octet on ternary machines?
[/QUOTE]
The requirement is to be able to represent at least 256 discrete values.
This can be accomplished in six trits, the relevant trit pattern being
100110.

What I was getting at was whether the definition of octet should be
taken to be 8 bits, or 8 whatsits (where whatsit = bit, trit, etc).
That is, can a six-trit word be considered to be smaller than an
octet, defeating the claim that a byte may not be smaller than octet?

-- Richard
 
R

Richard Heathfield

Richard Tobin said:
The requirement is to be able to represent at least 256 discrete
values. This can be accomplished in six trits, the relevant trit
pattern being 100110.

What I was getting at was whether the definition of octet should be
taken to be 8 bits, or 8 whatsits (where whatsit = bit, trit, etc).[/QUOTE]

Oh, I see.
That is, can a six-trit word be considered to be smaller than an
octet, defeating the claim that a byte may not be smaller than octet?

The C Standard makes no such claim. It only makes the claim that a byte
must be at least 8 bits wide. If we accept the possibility of a ternary
machine, the minimum number of trits that would do the trick is 6.

As far as I can tell, the word 'octet' doesn't appear in the Standard.
 
R

Richard Tobin

glen herrmannsfeldt said:
As someone else mentioned, %zu has been added to solve the problem.

I'd never noticed that before. Nor had I noticed %jd and %td.

-- Richard
 
Ad

Advertisements

R

robert bristow-johnson

grumble, grumble...

okay guys we can argue a little bit about the sizes of types, but
isn't it clear that when i run these lines of code:

a_ulong = 1234567;

a_short_array[26] = a_ulong;

printf("%d, %hx, %x, %lx \n", sizeof(a_short_array),
a_short_array[26], a_short_array[26], a_ulong );

and get this for output:

256, d687, ffffd687, 12d687

that the bits in the hex digits "12" went bye-bye in the assignment
statement? i just wanna know what flag to set (if any) that makes the
compiler tell me i might want to check the statement that could
potentially throw away those bits. i would think, from the
description that -Wconversion or -Wall should do it, but it doesn't
and i was wondering if the hardcore C or gcc geeks might know the
magic invocation to generate such a warning.

i'm no linux or gnu freak (really a neophyte), i just remember in my
old codewarrior days that there was a nice little check box i could
hit to see such warnings. killing such warnings is a useful
discipline to have to avoid some unforseen bugs that might also be
hard to find. it's sorta like enforcing strict type checking.

r b-j
 

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

Top