6

I have the uint64_t constants in my C++ program (clang 6.0.1 in QtCreator 4.6.1).

For example:

uint64_t a = 0xffffffffffffffffULL;

The problem is, that I get the following warning in the IDE:

Warning: implicit conversion from 'unsigned long long' to 'uint64_t' (aka 'unsigned long')

I tried also to change it to the following without success :

uint64_t a = UINT64_C(0xffffffffffffffff);
uint64_t a = 0xffffffffffffffffUL;

I have options to compute with C++14 standard and option: -Wconstant-conversion

Checking the types size:

std::cout << "uint64_t " << sizeof (uint64_t) << std::endl; 
std::cout << "unsigned long " << sizeof (unsigned long) << std::endl;
std::cout << "unsigned long long " << sizeof (unsigned long long) << std::endl;

Result:

uint64_t 8  
unsigned long 8
unsigned long long 8

Any idea how to fix this and why IDE thinks that size conversion is happening?

Edit: I just checked the macro expansion:

define UINT64_C(c)  c ## UL

This means that provided example should work, however it doesn’t:

uint64_t a = 0xffffffffffffffffUL;
Ross
  • 2,079
  • 2
  • 22
  • 26
  • 2
    The answer is in your warning message! Read it carefully. – Some programmer dude Jul 21 '18 at 05:54
  • 1
    Possibly related: [question 1](https://stackoverflow.com/questions/48909995/best-proper-way-to-define-uint64-t-constants/48910449), [question 2](https://stackoverflow.com/questions/22363102/how-to-input-int64-t-uint64-t-constants) – njuffa Jul 21 '18 at 05:55
  • @Someprogrammerdude - Yes I tried. Updated the question with example. No the answer is not in the warning. – Ross Jul 21 '18 at 05:55
  • @Ross Congratulations. You're working with a 64 bit architecture. – πάντα ῥεῖ Jul 21 '18 at 05:58
  • @πάνταῥεῖ, 64 bit with LP64/IPL64 data model: https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models. Native windows uses LLP64 an UL suffix will be not portable between LP64 and LLP64 models – osgx Jul 21 '18 at 05:59
  • Ross, check https://stackoverflow.com/a/22363263/196561 for `UINT64_C` macro from `` header. – osgx Jul 21 '18 at 06:08
  • @πάνταῥεῖ Yes, it is 64bit. What is your point? – Ross Jul 21 '18 at 06:10
  • @osgx If you read carefully the question, you can see I have already tried this. – Ross Jul 21 '18 at 06:11
  • What warnings do you get with the two alternatives that didn't work? –  Jul 21 '18 at 06:16
  • @hvd The warnings are the same: Warning: implicit conversion from 'unsigned long long' to 'uint64_t' (aka 'unsigned long') – Ross Jul 21 '18 at 06:20
  • @Ross, Please provide complete minimal example of code (https://stackoverflow.com/help/mcve), command of clang++ to compile the example outside the IDE and project settings of QTC to get hints about how it may start clang++. With https://godbolt.org/ and my example I can't get clang++ 6 to print any warning for UINT64_C. – osgx Jul 21 '18 at 06:21
  • 3
    @Ross If your compiler sees `0xffffffffffffffffUL` as an `unsigned long long` constant (since you say the error still says "conversion from 'unsigned long long'"), then your `unsigned long` type doesn't have 64 bits. If your headers nonetheless define `uint64_t` as `unsigned long`, then something is seriously wrong. Are you somehow accidentally using another platform's headers? That doesn't match the test program's output, though. –  Jul 21 '18 at 06:22
  • 1
    @hvd This indeed seems to be problem with mixed headers. I tried to copy the definition in another file and the warning is not shown in it. – Ross Jul 21 '18 at 06:38

5 Answers5

3

unsigned long long is at least 64 bits, so it could be a bigger type than uint64_t

I would write (note the use of constexpr because it's a constant):

#include <cinttypes>
#include <limits>
constexpr auto a = std::numeric_limits<std::uint64_t>::max();

And to define a non-max uint64_t constant in portable way, just remove the ULL part at the end:

constexpr std::uint64_t b = 0x12345;
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Olivier Sohn
  • 1,292
  • 8
  • 18
  • Equal or bigger. 64 bits, not bytes. Depending on data model: https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models. How to define non-max constant in portable way? – osgx Jul 21 '18 at 06:01
  • @bit_data_models nice catch for bytes -> bits. What do you mean by Equal or bigger? I said "at least" in my answer, which is the same as equal or bigger. No? – Olivier Sohn Jul 21 '18 at 06:06
3

This warning is resolved thanks to @hvd comment.

Checked all included header files. For some reason, both stdint.h and cstdint were included. I left only the cstdint. They are probably from different platforms and have different definitions.

The working example:

uint64_t v0 = UINT64_C(0x736f6d6570736575);
Ross
  • 2,079
  • 2
  • 22
  • 26
  • Macros are evil - and hardly ever needed. – Sid S Jul 21 '18 at 07:05
  • 1
    What happens if only `stdint.h` included? Or if only `cstdint`? Presumably, for one of these cases, you'll get the same bogus warning (it should not be a problem, if both included). "They are probably from different platforms and have different definitions.": this means that your installation is incorrect. – geza Jul 21 '18 at 07:08
0

The compiler is warning you of an implicit conversion between types that are not guaranteed to be of the same size in C++. A possible fix is to make it explicit:

uint64_t a = static_cast<uint64_t>(0xffffffffffffffffULL);
user4815162342
  • 141,790
  • 18
  • 296
  • 355
0

This is one way to do it :

auto a = static_cast<uint64_t>(-1);
Sid S
  • 6,037
  • 2
  • 18
  • 24
-1

The first thing to note here is that you don't need the LL suffix.

An integer literal automatically will have a type which can hold the number. Check out this table for exact types. The only exception to this rule is if you specify a decimal literal which only fits to unsigned long long int. Then you need to specify the u suffix.

Now, the warning can be removed easily with a cast:

uint64_t a = (uint64_t)0xffffffffffffffff;

or if you don't like C cast, then with static_cast:

uint64_t a = static_cast<uint64_t>(0xffffffffffffffff);


So far, this was the theory, but you have some problems with your compiler/installation. If you have the implicit conversion warning for this:

uint64_t a = 0xffffffffffffffffUL;

where uint64_t is unsigned long, then it means that 0xffffffffffffffffUL actually becomes unsigned long long int. But it should not be, as sizeof(unsigned long) is 8 already. This is clearly an impossible situation, if the compiler and installation is correct.

geza
  • 28,403
  • 6
  • 61
  • 135