7

I have this school assignment in C where I will be corrected with the following flags :

-Wall -Wextra -Werror

So this harmless warning becomes an error and prevents compilation :

integer literal is too large to be represented in a signed integer type

(code still works) but if I can't mute it my work will be considered wrong

Here is my code :

static unsigned long long   piece_to_map(unsigned short little)
{
    static unsigned short   row;
    unsigned long long      big;
    char                    i;
    unsigned long long      mask_left;
    unsigned long long      mask_top;

    mask_left = 9259542123273814144;
    mask_top = 18374686479671623680;
    row = 15;
    big = 0;
    i = 0;
    while (i < 16)
    {
        big |= (little & (row << i)) << i;
        i += 4;
    }
    while ((big & mask_t) == 0)
        big = big << 8;
    while ((big & mask_l) == 0)
        big = big << 1;
    return (big);
}

What I'm trying to achieve here is to transform an unsigned short (representing a shape in a 4x4 square) to an unsigned long long representing the same shape in a 8x8 square having the shape cornered top-left. It works perfectly and according to my expectations, I just need to avoid having the warning. I was formerly using the (normally equivalent) binary expression instead and didn't get any warning

0b1111111100000000000000000000000000000000000000000000000000000000

and

0b1000000010000000100000001000000010000000100000001000000010000000

The problem is that the 0bxxxx form is not standard C (As I read in this StackOverflow answer), therefore I am not allowed to use it.

I also tried

mask_left = (unsigned long long)9259542123273814144;
mask_top = (unsigned long long)18374686479671623680;

The compiler still tells me that the value is too large to be represened in a signed integer type. What am I doing wrong ? Is there any way to fix this at all ?

Community
  • 1
  • 1
M. Kejji
  • 163
  • 1
  • 1
  • 6
  • 12
    This is not a harmless warning. – Iharob Al Asimi Feb 01 '16 at 17:06
  • 1
    `9259542123273814144` is a integer literal, `9259542123273814144L` is a long integer literal. – tkausl Feb 01 '16 at 17:07
  • without the compiling flags, it is just a warning and the compilation succeeds. With the flags it's an error and the compilation fails. That's what I meant by "harmless" @tkausl : thank you, I had never known about suffixes like that – M. Kejji Feb 01 '16 at 17:23
  • It's in no way harmless: It's an overflow of a signed integer type, causing *undefined behavior*. That program could've started a new world war or killed some kittens! – Daniel Jour Feb 01 '16 at 17:52
  • @tkausl Both `9259542123273814144` and `9259542123273814144L`, as attempted un-suffixed decimal integer constants, exceed `LLONG_MAX` and do not fit. Note: C does not specify _integer literal_. It does specify _integer consonants_. – chux - Reinstate Monica Feb 01 '16 at 18:22

3 Answers3

17

Implicitly, the integer literal is signed and of course the values are too big for a signed long long, so you need to let the compiler know that they have type unsigned, like this

mask_left = 9259542123273814143U;
mask_top = 18374686479671623680U;
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • I had never heard about suffixes like that :D Thank you ! This is exactly what I was trying to achieve by casting the litteral in my second try – M. Kejji Feb 01 '16 at 17:24
  • 1
    "the integer literal has type `int`". No. `decimal literals can be `int`, long` or `long long`. The issue is that both constants exceed `LLONG_MAX` or `9223372036854775807` – chux - Reinstate Monica Feb 01 '16 at 17:53
  • 1
    Much better. Detail: un-suffixed decimal integer _constants_ are signed. OP could have done `mask_left = 0x8080808080808080; mask_top = 0xFF00000000000000;` which are hexadecimal integer _constants_ and would have quietly been unsigned as needed. IMO, OP should be using hex _constants_ for masks anyways. – chux - Reinstate Monica Feb 01 '16 at 18:22
  • Thank you chux, I am new to binary operations, masks, shifting etc... I will note this advise for my next works – M. Kejji Jun 01 '16 at 12:17
9

Rewrite it with explicit size:

mask_left = 9259542123273814144uLL;
mask_top = 18374686479671623680uLL;

By writing it as (unsigned long long) 9259542123273814144 it means to take the integer and then cast it longer. Unfortunately, the integer is probably munged (by throwing away the higher bits to make it an int) and then increasing the size.

wallyk
  • 56,922
  • 16
  • 83
  • 148
  • The "LL" is not needed. The size explcit-ness is not the issue. The problem is that `9259542123273814144 > LLONG_MAX`, so the compiler, beyond C specifications, finds the values fit as unsigned literals. (`unsigned long long`) as so warns. – chux - Reinstate Monica Feb 01 '16 at 18:16
3

Signed integer literals cannot be larger than 2147483648. For a number larger than that, you need to add the LL prefix, which tells the compiler it is a long long. In your case, you want ULL as that designates an unsigned long long, which is what you're assigning to.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • 1
    "Signed integer literals cannot be larger than 2147483648" is incorrect. Signed integer literals cannot be larger than `LLONG_MAX` which is at least `9223372036854775807` or `pow(2,63)-1` – chux - Reinstate Monica Feb 01 '16 at 17:50