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

  • Thread starter robert bristow-johnson
  • Start date
G

glen herrmannsfeldt

Richard said:
Richard Tobin said:
(snip)
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.

C sort of expects a binary representation. Unsigned addition is
module some power of two, and bitwise operators would be very slow
otherwise.

Fortran specifically allows any base greater than one. That would
be a better place to look for a ternary machine. (Fortran has bitwise
operations as intrinsic functions. It isn't so obvious what they would
do on a non-binary machine.)

-- glen
 
J

Jack Klein

K

Keith Thompson

Jerry Avins said:
Do you have a better "rule" than mine to tell just how many that '+'
implies?

A byte is exactly the size of a character (an object of type char).

A byte is at least 8 bits (i.e., >= 1 octet).

A byte is an addressable unit of data storage (i.e., at least as big
as the smallest addressible storage element).

Systems for which the natural size of a character is less than 8 bits,
or where a character is not addressable, are shown no mercy; they must
adapt somehow in order to be conforming. For example, on Cray vector
systems, a character is 8 bits, but the smallest physically
addressable storage unit is 64 bits. The C compiler fakes 8-bit
addressability by storing the byte offset in the high-order bits of a
pointer. There's no hardware support for this; it's done in software
(i.e., by the machine code generated by the compiler). (CHAR_BIT
*could* have been set to 64 rather than 8, but that would have broken
interoperation with other systems.)
 
M

Martin Ambuhl

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
^^^^^
always. An int is signed, a size_t is unsigned. sizeof(type) is a
size_t.
sizeof(sizeof(int))==sizeof(int)

Why?
 
R

Randy Yates

robert bristow-johnson said:
robert bristow-johnson said:
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?

Yes. the C Standard does not require implementations to produce a
diagnostic message in this circumstance. A conversion is supplied. Of
necessity, if the lvalue is less wide than the rvalue, any information
stored in those extra bits will be lost. Nevertheless, the conversion
is a useful one in situations where no information is lost, and to take
advantage of it does not constitute a syntax error or constraint
violation, so no diagnostic message is required.

it just seems to me that this conversion qualifies as one that changes
value. then, according to the gcc doc, it should generate a -
Wconversion warning.

From the manual:

-Wconversion Warn if a prototype causes a type conversion that is
different from what would happen to the same argument in the absence
of a prototype. This includes conversions of fixed point to floating
and vice versa, and conversions changing the width or signedness of
a fixed point argument except when the same as the default
promotion.

Also, warn if a negative integer constant expression is implicitly
converted to an unsigned type. For example, warn about the
assignment x = -1 if x is unsigned. But do not warn about explicit
casts like (unsigned) -1.

What do they mean by "prototype"?

No matter what the documentation says or the standards say, I also
find this situation extremely frustrating and counter-productive.

It seems like the compiler emits warnings (or errors) all the time on
type conversions of little consequence, and yet when it comes to
something that causes a real loss of information, it remains silent.

This behaviour ought to be changed.
--
% Randy Yates % "And all that I can do
%% Fuquay-Varina, NC % is say I'm sorry,
%%% 919-577-9882 % that's the way it goes..."
%%%% <[email protected]> % Getting To The Point', *Balance of Power*, ELO
http://home.earthlink.net/~yatescr
 
G

glen herrmannsfeldt

Keith Thompson wrote:

(snip)
An "octet" is by definition 8 bits. If you don't have bits, you can't
have octets. Of course a ternary machine can emulate bits; the answer
to your question then depends on how the emulation is done.
If you use ternary machines, it might be reasonable to refer to a
collection of 8 trits as an "octet". That would conflict with normal
usage, but then so do ternary machines.

Ternary machines are rare, but machines that can do decimal
arithmetic aren't so rare. Even x86 can do it, though not all
that easily.

Soon there will be machines that can do floating point decimal
arithmetic, as far as I know C allows that.

-- glen
 
G

glen herrmannsfeldt

Jerry Avins wrote:
(snip)
Isn't a byte in C the larger of character, octet, or smallest
addressable storage element?

There are complications on some word addressable machines.

For the PDP-10 it is suggested that CHAR_BIT be either 9 or 18.
While its addressable unit is the 36 bit word, there are
instructions to directly address halfwords, and it isn't so hard
to address 9 bit bytes.

There are stories of C compilers for the PDP-10, though they
are not easy to find.

-- glen
 
G

glen herrmannsfeldt

CBFalconer said:
Vladimir Vassilevsky wrote:
(snip)
No it can't. Read the standard. Chars may be bigger than 8 bits,
but the size of a char is the same as the size of a byte. C is
peculiar that way.

It depends on context.

If one wrote a C program to print out the available
disk space on a system, the user might expect it to be in
eight bit bytes, even when CHAR_BIT was not 8.

But yes, sizeof (which is not a function) units are
sizeof(char), and are called bytes independent of the
actual size.

-- glen
 
J

jaysome

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).

The C standard screwed up when it chose to use the term "byte" to
refer to what is really a storage unit. Everyone who owns a hard drive
knows that a byte is 8 bits. So do most programmers, regardless of
their programming language choice.

The Ada standard got it right, because it chose to use the term
"storage unit" to refer to what the C standard refers to as a "byte".
Ada83 pre-dates C90 by enough years--go figure.
 
K

Keith Thompson

jaysome said:
The C standard screwed up when it chose to use the term "byte" to
refer to what is really a storage unit. Everyone who owns a hard drive
knows that a byte is 8 bits. So do most programmers, regardless of
their programming language choice.

The term "byte" was in widespread use for a number of years before the
meanings other than 8 bits became rare.
 
F

Flash Gordon

Richard Tobin wrote, On 05/06/07 23:14:
How big is an octet on ternary machines?

Irrelevant. Integer types (including char) are required to use a pure
binary representation :)
 
J

jacob navia

robert said:
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
Do not know about gcc, but lcc-win32 produces:
Warning twarn.c: 14 Assignment of unsigned long to short. Possible loss
of precision.

You have to use a higher warning level:
lcc -A twarn.c

In general, lcc-win32 warns when sizes differ in an assignment, the
recipient being smaller than the source.
 
C

Chris Dollin

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

I'm going to ignore your real problem [1] in favour of criticising your
subject line:

... implicit casts ...

C doesn't have implicit casts. Casts are explicit syntax, `(Type) Expr`.
It has implicit /conversions/.

I'll have another latte now.

[1] Which I see has generated much -- hopefully helpful -- response.

--
"It was the first really clever thing the King had said that day."
/Alice in Wonderland/

Hewlett-Packard Limited registered no:
registered office: Cain Road, Bracknell, Berks RG12 1HN 690597 England
 
R

robert bristow-johnson

robert bristow-johnson said:
it just seems to me that this conversion qualifies as one that changes
value. then, according to the gcc doc, it should generate a -
Wconversion warning. it's close to an assignment of one type to
another but less severe. for example, if sizeof(unsigned
short)<sizeof(long) we know that no value is changed in this
assignment:

unsigned short a_ushort;
long a_long;
a_ushort = 4321;
a_long = a_ushort;

so no warning should be generated, no matter what bits are in
a_ushort, there is no change of value. whereas (assuming
sizeof(short)<sizeof(unsigned long)) this:

short a_short;
unsigned long a_ulong;
a_short = -4321;
a_ulong = a_short;

should generate a warning because there are values in the range of the
type (short) that are not in the type (unsigned long). so even if the
number of bits in the word are increasing in the assignment, this
should generate a -Wcondition warning ...

i meant to say "generate a -Wconversion warning"


From the manual:

-Wconversion Warn if a prototype causes a type conversion that is
different from what would happen to the same argument in the absence
of a prototype. This includes conversions of fixed point to floating
and vice versa, and conversions changing the width or signedness of
a fixed point argument except when the same as the default
promotion.

Also, warn if a negative integer constant expression is implicitly
converted to an unsigned type. For example, warn about the
assignment x = -1 if x is unsigned. But do not warn about explicit
casts like (unsigned) -1.

What do they mean by "prototype"?

i function prototype (i think that's what they mean) is when you put
at the top of a C file (or in a header file) the declaration such as:

double my_math_function(double argument1, long argument2);

(not the semicolen at the end). it can be abbreviated as so:

double my_math_function(double, long);

what i like to do is just copy the top line of the function when i
write it, paste it in the header file, tack on a semi-colen to the end
of it and then feel good and smug that i was obeying good coding
practices in C. in CodeWarrior, there is another check box that says
"Require prototypes" and an error will be generated if you define or
call a function without prototyping it. it's just another little type-
checking discipline that can save your ass at a later date.

i remember once, programming a 68K Mac without requiring prototypes,
and i made a simple call to a standard trancendental function (like
sin() or exp()) but i forgot to #include <math.h>. so the calling
function assumed (by default, since there was no prototype) that sin()
returned int which was 16 or 32 bits, but it really returned double or
extended (64 or 80 bits) and placed that return value on the stack
above the PC. so even though it was automatically linked to the math
lib when i built the app, what happened was that the calling program
(my code) did not reserve sufficient space on the stack for the return
value and the called program plopped a big 64 bit or bigger word than
the space that was made and my machine crashed. it was a stupid and
hard bug to fix because i couldn't understand why calling a standard
math function would crash the machine. i actually single-stepped
through this before realizing that i forgot to #include the header
file with the correct prototypes which was the source of the problem.
ever since then, i've become a believer in building projects with
prototypes required (except maybe if the function is defined in the
same C file it is called, and called *only* in that file, and defined
*before* it is called).
No matter what the documentation says or the standards say, I also
find this situation extremely frustrating and counter-productive.

It seems like the compiler emits warnings (or errors) all the time on
type conversions of little consequence, and yet when it comes to
something that causes a real loss of information, it remains silent.

This behaviour ought to be changed.

i agree. it seems to me to be standard that an *implicit* conversion
that potentially changes value (whether or not there is a bit
reduction) should, at least as an option, be flagged. (explicit casts
need not flag a warning, the compiler can assume you knew what you
were doing.) when you are building a big project with a couple
hundred files with interconnected spagetti code and some value got
clobbered (more precisely "clipped" or masked) because one guy thought
we were dealing with shorts and another thought longs (or signed longs
vs. unsigned longs, whatever), we should be informed by the compiler
when such conversions are made, whether in a simple assignment or in
passing a value to a function (that was expecting a slightly different
type).

i'm afraid this is like that stupid MATLAB/Octave indexing thing (all
arrays must start with index 1). it's something that obviously should
be fixed, but those with the where-with-all to fix it will deny that
it's a problem to start with (i guess that's one way to fix a problem
- deny the existence of it).

r b-j
 
J

jacob navia

CBFalconer said:
I don't think he cares about normal Usenet protocol. He certainly
ignores topicality here.

Mmm This thread is about a gcc warning. Obviously gcc is
on topic, but lcc-win32 is not.

Why?

Because linux is cool and windows is not apparently. Or because
anything I say is off topic.

At any rate, there is a large difference between:

shortthing = bigthing;
and
shortthing = (shorttype)bigthing;

in that the second has already performed the conversion, and
nothing is lost thereafter.

I know that.
 
R

Richard Heathfield

jacob navia said:
Mmm This thread is about a gcc warning. Obviously gcc is
on topic, but lcc-win32 is not.

No, gcc is off-topic here, just like lcc-win32 is off-topic here. The
proper course for respondents would have been to examine the source the
OP provided, to see whether the issue could somehow be resolved using
standard C. If not, they should have referred the OP to a gcc-specific
group.

<snip>
 
K

Keith Thompson

CBFalconer said:
At any rate, there is a large difference between:

shortthing = bigthing;
and
shortthing = (shorttype)bigthing;

in that the second has already performed the conversion, and
nothing is lost thereafter.

Assuming that shortthing is of type shorttype, there's no semantic
difference. The same conversion is performed in both cases; it's just
implicit in the first, and explicit in the second. (And in the second
case, it might be promoted after the cast and then narrowed for the
assignment, but I don't think that can have any visible effect, and a
compiler is likely to optimize it out.)

A compiler might reasonably warn in one case but not in the other, but
there's no requirement for it to do so.
 
J

jacob navia

Keith said:
Assuming that shortthing is of type shorttype, there's no semantic
difference. The same conversion is performed in both cases; it's just
implicit in the first, and explicit in the second. (And in the second
case, it might be promoted after the cast and then narrowed for the
assignment, but I don't think that can have any visible effect, and a
compiler is likely to optimize it out.)

A compiler might reasonably warn in one case but not in the other, but
there's no requirement for it to do so.

lcc-win32 does NOT warn when the programmer explicitely casts
the assignment since it assumes that the programmer knows
about that particular data representation and it supposes
that the cast is safe.

When there is an implict conversion however, it could be due
to an oversight or an error, and in that case a warning is
useful.
 

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
474,471
Messages
2,571,831
Members
48,802
Latest member
shadowoftheunknown
Top