How do you specify a 64 bit unsigned int const 0x8000000000000000 in VS2008?
Asked Answered
M

2

25

I read about the Microsoft specific suffix "i64" for integer constants. I want to do an UNsigned shift to a ULONGLONG.
ULONGLONG bigNum64 = 0x800000000000000i64 >> myval;

In normal C, I would use the suffix "U", e.g. the similar 32 bit operation would be
ULONG bigNum32 = 0x80000000U >> myval;

I do NOT want the 2's complement sign extension to propogate through the high bits. I want an UNSIGNED shift on a 64 bit const number. I think my first statement is going to do a SIGNED shift right.

I tried 0x800000000000000i64U and 0x800000000000000u64 but got compiler errors.

Mangan answered 14/5, 2010 at 16:17 Comment(3)
In my Visual Studio, limits.h has the syntax 0xffffffffffffffffui64, so 0x800000000000000ui64 should work. However, it's a newer version, so maybe it didn't work in Visual Studio 2008.Helmholtz
@M.M: U can be unsigned int, unsigned long int, or unsigned long long int for a hex integer constant. UL can be either unsigned long int or unsigned long long int. See 6.4.4.1 of the C standard (or 2.14.3 of the C++ standard). Given that, I don't think the OP's example is incorrect or needs modification.Continent
This is an older question. In C++11, I don't think any suffix is necessary. Only an unsigned 64-bit integral type can hold that constant. An unsigned long long must be at least 64-bit, and that's on the list of types the compiler should try for a literal in hexadecimal format. en.cppreference.com/w/cpp/language/integer_literalFoch
C
38

You can use the suffix ull, which is the standard (C99 and C++0x) way to specify an unsigned long long integer literal, and a long long is at least 64 bits.

Cecelia answered 14/5, 2010 at 16:19 Comment(6)
Compiler warning -Wlong-long can be disabled on the compiler command line or in the code with #pragma GCC diagnostic ignored "-Wlong-long". Here's a nice example of doing this temporarily for a section of code.Otisotitis
@BobStein-VisiBone: You will not receive any warnings for anything related to long long if you are compiling in C99 mode or higher.Quass
@AnT I have -std=gnu99 which is the way to compile in C99 mode in AtmelStudio. And I get warning: use of C99 long long integer constant [-Wlong-long] I do enable the warning by default because it's a 32-bit MCU and I want to use 64-bit math sparingly.Otisotitis
@BobStein-VisiBone: Is this really "the way" to compile in C99 mode there? The answer you linked does not seem to say that the normal -std=c99 won't work. Correct me if I'm wrong, but to me -std=gnu99 sounds like a personal preference of the person that gave that answer (with certain holywar-ish attitude, since he didn't even bother to mention -std=c99).Quass
@AnT wow maybe the plot is thicker than I thought. Are you saying in real C99 mode there should be no way to enable warnings on LL suffixes? That -Wlong-long does nothing? Or just that it's off by default.Otisotitis
@BobStein-VisiBone: There should be a way to enable them, if you so desire by using an explicit -Wlong-long. But I'd expect them to be off by default.Quass
C
14

Funny enough, but you don't actually need to add any suffix to your hex constant in order for it to be treated correctly. Section 6.4.4.1 of the C standard and section 2.14.3 of the C++ standard contain the following table:

Suffix       | Decimal Constant       | Octal or Hexadecimal Constant
-------------+------------------------+------------------------------
none         | int                    | int
             | long int               | unsigned int
             | long long int          | long int
             |                        | unsigned long int
             |                        | long long int
             |                        | unsigned long long int
-------------+------------------------+------------------------------
u or U       | unsigned int           | unsigned int
             | unsigned long int      | unsigned long int
             | unsigned long long int | unsigned long long int
-------------+------------------------+------------------------------
l or L       | long int               | long int
             | long long int          | unsigned long int
             |                        | long long int
             |                        | unsigned long long int
-------------+------------------------+------------------------------
Both u or U  | unsigned long int      | unsigned long int
and l or L   | unsigned long long int | unsigned long long int
-------------+------------------------+------------------------------
ll or LL     | long long int          | long long int
             |                        | unsigned long long int
-------------+------------------------+------------------------------
Both u or U  | unsigned long long int | unsigned long long int
and ll or LL |                        |

This table tells us what type an integer constant will have. The integer constant's type will be the first type in which it the value fits.

This means that the compiler will iterate through the following types for the hexadecimal constant 0x800000000000000 (it has no suffix, so it uses the "none" row, and it's a hex constant, so it uses the "Hexadecimal Constant" column), and it will use the first type which can store that value*:

  1. int: No, a 32-bit signed integer can't store this value.
  2. unsigned int: No, a 32-bit unsigned integer can't store this value.
  3. long int: No, a 32-bit signed integer can't store this value.
  4. unsigned long int: No, a 32-bit unsigned integer can't store this value.
  5. long long int: No, a 64-bit signed integer can't store this value.
  6. unsigned long long int: Yes, a 64-bit unsigned integer can store this value. Since this is the first type that can fully store the value, this is the type that the integer constant will have.

So, to answer your question of "How can I write and use the value 0x800000000000000 and make sure the compiler won't treat the high bit as a sign bit?": Simply just write unsigned long long value = 0x800000000000000.

If you want to do some bitwise arithmetic with the value, you can just go ahead and do that (i.e. just write 0x800000000000000 >> myval). You're guaranteed that it will not be treated as an overflowed signed integer, and your right shift won't do any sign extension because it's a positive value.

*I'm assuming that int is 32-bits, long is 32-bits, and long long is 64-bits. Note that your compiler might use different bit sizes for these types, which may change the end result (though the process will still be the same).

Continent answered 23/3, 2016 at 0:46 Comment(5)
You need to be careful though. If you want to declare a unsigned long long without a suffix, then you will get into trouble: consider printf("%lx\n", (0x40000000<<1)>>1); The left/right shift should give back 0x40000000, but if you run this, you will get 0xc0000000.Accentual
using %l treats the value as a signed integer or signed long. If you take the 2's complement of 0xc0000000 you will get 0x40000000, but this would represent a negative number. Cornstalks is correct, because the value was declared as unsigned long long. If I declare them as signed ints then I get 0xc0000000:Cistaceous
I wasn't able to finish my comment: printf("%lx\n", (0x40000000<<1)>>1); // treats the values as signed instead of unsigned. unsigned int a = 0x40000000; unsigned int b = a<<1; unsigned int c = b>>1; printf("%lx\n", c); // you would get 0x40000000. This is because without a suffix, the none row is used and both 0x40000000, 0x80000000, and 0xc0000000 can be represented as signed integers. Which is exactly what Cornstalks said, and they are correct.Cistaceous
Moreover, printf defaults to unsigned hex without a format specifier, but this that format-specifier is not the same thing as a constant specifier that goes after a constant value. For to print out 64-bit values with printf, %lx, must be used and you must specifically define a variable of the appropriate type -- but again this is only for printing and has no affect on arithmetic operations. It should be noted that at some point the c++ compiler (g++, etc) will allow this: unsigned long long int k = 0x800000010000000; unsigned int z =k; z will be 0x10000000.Cistaceous
The question is specific to Visual Studio, so ok. But I don't think there's any guarantee in the language that long long is NOT 128bits, whereby a signed 128bit integer would make the shift fail.Pelson

© 2022 - 2025 — McMap. All rights reserved.