• Overflow in constant expression

    From jacobnavia@21:1/5 to All on Sun Oct 28 10:42:02 2018
    XPost: comp.lang.c

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to jacobnavia on Sun Oct 28 13:24:59 2018
    XPost: comp.lang.c

    On 28/10/2018 10:42, jacobnavia wrote:
    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"...

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ike Naar@21:1/5 to jacobnavia on Sun Oct 28 19:34:03 2018
    XPost: comp.lang.c

    On 2018-10-28, jacobnavia <jacob@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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to jacobnavia on Sun Oct 28 19:41:26 2018
    XPost: comp.lang.c

    Newsgroups: comp.lang.c,comp.compilers.lcc


    jacobnavia <jacob@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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jacobnavia@21:1/5 to All on Sun Oct 28 21:10:23 2018
    XPost: comp.lang.c

    Le 28/10/2018 à 20:34, Ike Naar a écrit :
    On 2018-10-28, jacobnavia <jacob@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.


    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!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jacobnavia@21:1/5 to All on Sun Oct 28 21:12:26 2018
    XPost: comp.lang.c

    Le 28/10/2018 à 20:41, Stefan Ram a écrit :
    Newsgroups: comp.lang.c,comp.compilers.lcc


    jacobnavia <jacob@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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to jacobnavia on Sun Oct 28 20:31:56 2018
    XPost: comp.lang.c

    jacobnavia <jacob@jacob.remcomp.fr> writes:
    I used
    -Wall -Wpedantic

    Maybe you can try to add:

    -Wfloat-conversion

    or

    -Wconversion

    . I use:

    -std=c18
    -O3
    -pedantic
    -pedantic-errors
    -g
    -Werror=narrowing
    -Wall
    -W
    -Wconversion
    -Wextra
    -Wno-parentheses
    -D__USE_MINGW_ANSI_STDIO
    -Wno-unused-parameter
    -Wno-unused-variable
    -Wno-empty-body
    -Wno-unused-but-set-variable
    -ftrapv

    , please note »-Wconversion« above, which might not be
    included within »-Wall«. I don't know about »-Wpedantic«,
    though.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jacobnavia@21:1/5 to All on Sun Oct 28 22:08:39 2018
    XPost: comp.lang.c

    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lew Pitcher@21:1/5 to jacobnavia on Sun Oct 28 17:12:27 2018
    XPost: comp.lang.c

    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"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From manu_bat_manu@yahoo.fr@21:1/5 to All on Sun Oct 28 14:38:27 2018
    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 ...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Keith Thompson@21:1/5 to jacobnavia on Sun Oct 28 16:07:23 2018
    XPost: comp.lang.c

    jacobnavia <jacob@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) kst@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"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)