Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Overflow in constant expression

368 views
Skip to first unread message

jacobnavia

unread,
Oct 28, 2018, 5:42:03 AM10/28/18
to
This warning should notify the user that a constant doesn't fit into the
expected type.

For instance

char m = 476;

or

double s = 1e456;

This happens also when assigning the result of a function, and in other
situations, for instance

_Bool h = 6;

Gcc however will warn sometimes, sometimes not.

Compiling the following program:

char s = 654;
_Bool h = 8;

float fnf(void) { return 1e145; }
_Bool error_p(int a)
{
int m = a != 0;
if (a != 0)
return 7;
return a != 0;
}

will produce the following warnings:

foo.c:1:10: warning: large integer implicitly truncated to unsigned type
[-Woverflow]
char s = 654;
^~~
foo.c: In function ‘error_p’:
foo.c:7:6: warning: unused variable ‘m’ [-Wunused-variable]
int m = a != 0;

It detects that the assignment to a char of the number 654 will overflow
but issues an otherwise incomprehensible warning:

"integer implicitely truncated to unsigned type"...

Well at least it says something.

No warnings will be issued for the overflow of assigning a float with a
constant that is beyond the dynamic range of the type, nor it will issue
a warnçing when assigning 7 to a bit...

Why is this?

Lcc-win issues a warning for all those cases. I am reviewing the
warnings of lcc-win and I would like to know if other compilers besides
gcc have the same behavior. The compiler flags I used were:

gcc -Wall -Wpedantic

Note that clang has the same behavvior as gcc but the wording of the
warnings is much clearer:

tretbool.c:1:10: warning: implicit conversion from 'int' to 'char'
changes value from 654 to -114 [-Wconstant-conversion]
char s = 654;

Still, no warnings are issued for the other cases.

David Brown

unread,
Oct 28, 2018, 8:25:01 AM10/28/18
to
That is not incomprehensible to me, but there is always scope for
improving the helpfulness of error messages in a compiler - this is
something gcc has worked on greatly in past years. So try it again with
a newer gcc - gcc 8 gives:

<source>:8:10: warning: overflow in conversion from 'int' to 'char'
changes value from '654' to '-114' [-Woverflow]

char s = 654;

^~~

This should be clearer, I think.


>
> Well at least it says something.
>
> No warnings will be issued for the overflow of assigning a float with a
> constant that is beyond the dynamic range of the type, nor it will issue
> a warnçing when assigning  7 to a bit...
>
> Why is this?

It is - arguably unfortunately - the way C works.

When you write something like "char s = 654;", the interpretation is
that "654" is an integer constant (it will be of type "int") which is
then assigned to the char "s". It is perfectly legal to assign such a
value - the conversion is implementation-defined (or can raise a signal)
if plain char is a signed type, or done as modulo wrap-around if it is
an unsigned type. (The gcc implementation-defined behaviour for
assigning to signed integer types is always modulo wrap-around too.)

It is all legal C and a conforming compiler should not reject any of the
code above (but it can warn about it). By default, gcc warns about the
overflow in assigning 654 to a char - the relevant warning option
"-Woverflow" is enabled by default.

The "-Wconversion" warning will warn about the conversion in "fnf" to
+Inff. I would have liked -Wconversion to be part of -Wall or at least
-Wextra, but it is not. (I like gcc, but I am not going to say it is
perfect!)


Conversion of something other than 0 or 1 to a boolean is so common in
code that there is no warning for it. I think it might be reasonable to
have a warning for cases like this initialisation or other uses of a
constant expression converted to a boolean, but you would not want it by
default.


>
> Lcc-win issues a warning for all those cases. I am reviewing the
> warnings of lcc-win and I would like to know if other compilers besides
> gcc have the same behavior.

Warnings are good - just be careful that warnings can give false
positives on legal code.

> The compiler flags I used were:
>

clang gives the same warnings.

<https://godbolt.org> is your friend here.

> gcc -Wall -Wpedantic

If you want to test more solid warning capabilities, you need more
flags. I'd add "-Wextra" to this, and in this particular case
"-Wconversion" is key.

gcc has a /lot/ of warning flags and it is not easy to know which would
be good to use. But for your research here, I'd recommend reading the
relevant page:

<https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html>

I am sure it will give you some new ideas.

>
> Note that clang has the same behavvior as gcc but the wording of the
> warnings is much clearer:
>
> tretbool.c:1:10: warning: implicit conversion from 'int' to 'char'
> changes value from 654 to -114 [-Wconstant-conversion]
> char s = 654;
>
> Still, no warnings are issued for the other cases.

(Newer versions of gcc have pretty much the same wording.)

Ike Naar

unread,
Oct 28, 2018, 3:34:04 PM10/28/18
to
On 2018-10-28, jacobnavia <ja...@jacob.remcomp.fr> wrote:
> _Bool error_p(int a)
> {
> int m = a != 0;
> if (a != 0)
> return 7;
> return a != 0;
> }
> [...] nor it will issue a warning when assigning 7 to a bit...
> Why is this?

It is not the case that 7 is assigned to a bit.
The value 7 is converted to _Bool, and the converted value
(here: 1) is assigned to the bit.

For a reference to the standard:

6.3.1.2 Boolean type
1 When any scalar value is converted to _Bool, the result is 0 if the
value compares equal to 0; otherwise, the result is 1.

jacobnavia

unread,
Oct 28, 2018, 4:10:25 PM10/28/18
to
Great!

But... that is the case for ALL constant expressions!

float m = 1e587;

1e587 is converted to float generating +inf, and THAT is stored into "m".

int32_t m = 12345678987654321112221;

The value is converted into int32_t and THAT value is stored into m.

etc.

The objective of the warning is just to WARN the user that there is an
error somewhere!

jacobnavia

unread,
Oct 28, 2018, 4:12:26 PM10/28/18
to
Le 28/10/2018 à 20:41, Stefan Ram a écrit :
> Newsgroups: comp.lang.c,comp.compilers.lcc
>
>
> jacobnavia <ja...@jacob.remcomp.fr> writes:
>> This warning should notify the user that a constant doesn't fit into the
>> expected type.
>
>
> What I get here from gcc with my standard options:
>
>
> warning: overflow in conversion from 'int' to 'char' changes value from '476' to '-36' [-Woverflow]
> | char m = 476;
> | ^~~
>
>
> warning: floating constant exceeds range of 'double' [-Woverflow]
> | double s = 1e456;
> | ^~~~~~
>
>
> warning: overflow in conversion from 'int' to 'char' changes value from '654' to '-114' [-Woverflow]
> | char s1 = 654;
> | ^~~
>
>
> main.c: In function 'fnf':
> warning: conversion from 'double' to 'float' changes value from '9.9999999999999999e+144' to '+Inff' [-Wfloat-conversion]
> | float fnf( void ){ return 1e145; }
> | ^~~~~
>
>
> Newsgroups: comp.lang.c,comp.compilers.lcc
>
>

Happy you.
I am using the version available for ARM64:
gcc version 6.3.0 20170516 (Debian 6.3.0-18+deb9u1)

I used
-Wall -Wpedantic

jacobnavia

unread,
Oct 28, 2018, 5:08:41 PM10/28/18
to
Le 28/10/2018 à 21:31, Stefan Ram a écrit :
> , please note »-Wconversion« above, which might not be
> included within »-Wall«

Gosh!

What a bad interface!

So, "all" doesn't mean all actually. There is always some hidden option
you do not know about.

"All" means "some" in gcc dictionary.

In any case those warniongs are necessary and my compiler issues them BY
DEFAULT. If you try to store a constant into a type too small to
faithfully preserve it, there is an ERROR SOMEWHERE. and the user should
be warned about it.

What I did not understand is why gcc didn't issue those. Now that I know
that it does issue them (using some hidden option) I know my warnings
are correct and there are no hidden problems.

Thanks for your input.

jacob

Lew Pitcher

unread,
Oct 28, 2018, 5:12:27 PM10/28/18
to
jacobnavia wrote:

> Le 28/10/2018 à 21:31, Stefan Ram a écrit :
>> , please note »-Wconversion« above, which might not be
>> included within »-Wall«
>
> Gosh!
>
> What a bad interface!

Opions differ.

> So, "all" doesn't mean all actually.

"all"? Where did you get "all" from?

The option under discussion is "-Wall", which is documented as
-Wall
This enables all the warnings about constructions that some users
consider questionable, and that are easy to avoid (or modify to
prevent the warning), even in conjunction with macros. This also
enables some language-specific warnings described in C++ Dialect
Options and Objective-C and Objective-C++ Dialect Options.

-Wall means "all warnings ABOUT CONSTRUCTIONS THAT SOME USERS CONSIDER
QUESTIONABLE", not "all warnings".



[snip]


--
Lew Pitcher
"In Skills, We Trust"

manu_b...@yahoo.fr

unread,
Oct 28, 2018, 5:38:28 PM10/28/18
to
Le dimanche 28 octobre 2018 10:42:03 UTC+1, jacobnavia a écrit :
> No warnings will be issued for the overflow of assigning a float with a
> constant that is beyond the dynamic range of the type, nor it will issue
> a warnçing when assigning 7 to a bit...
>

As an happy user of lcc-win32 (and 64 bits), this warning on boolean misuse has helped me some times. When a boolean become a "trolean" (0,1, and I add '2' because, well there is 'YES' 'NO' and 'CANCEL' for example) [not good practice, but real life ones].

So, yes GCC (that I use on ARM devices - microcontroller) didn't warn anything by default against this, and let long debug section to understand *why* the value is lost.
I will have a look to the -Wconversion

In general GCC & clang warnings is a vast area, that start to become a bit tricky when 'treat warnings as error' is involved in heavy toolchains (Android AOSP vs Android NDK in my case), and that didn't produce same warnings ...

Keith Thompson

unread,
Oct 28, 2018, 7:07:29 PM10/28/18
to
jacobnavia <ja...@jacob.remcomp.fr> writes:
[...]
> Great!
>
> But... that is the case for ALL constant expressions!
>
> float m = 1e587;
>
> 1e587 is converted to float generating +inf, and THAT is stored into "m".

Converted from what? Unlike integer constants, floating constants do
not have a type that depends on their value. An unsuffixed constant
has type double. (Add f or F to make it float, l or L to make it
long double). 1e578 typically exceeds DBL_MAX, so it violates the
constraint in 6.4.4p2, "Each constant shall have a type and the
value of a constant shall be in the range of representable values
for its type." A diagnostic is required for 1e587 regardless of
the context in which it appears. (One compiler I tried sets m to inf,
but the behavior is undefined if it compiles at all.)

> int32_t m = 12345678987654321112221;
>
> The value is converted into int32_t and THAT value is stored into m.

12345678987654321112221 is more than 2**73, so in most implementations
it would be a constraint violation. (If long long is wide enough to
hold the value, the conversion yields an implementation-defined result.)

[...]

--
Keith Thompson (The_Other_Keith) k...@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
0 new messages