Very basic question: how do I write a short literal in C++?
I know the following:
2 is an int
2U is an unsigned int
2L is a long
2LL is a long long
2.0f is a float
2.0 is a double
'\2' is a char.
But how would I write a short literal? I tried 2S but that gives a compiler warning.
((short)2)
Yeah, it's not strictly a short literal, more of a casted-int, but the behaviour is the same and I think there isn't a direct way of doing it.
That's what I've been doing because I couldn't find anything about it. I would guess that the compiler would be smart enough to compile this as if it's a short literal (i.e. it wouldn't actually allocate an int and then cast it every time).
The following illustrates how much you should worry about this:
a = 2L;
b = 2.0;
c = (short)2;
d = '\2';
Compile -> disassemble ->
movl $2, _a
movl $2, _b
movl $2, _c
movl $2, _d
C++11 gives you pretty close to what you want. (Search for "user-defined literals" to learn more.)
#include <cstdint>
inline std::uint16_t operator "" _u(unsigned long long value)
{
return static_cast<std::uint16_t>(value);
}
void func(std::uint32_t value); // 1
void func(std::uint16_t value); // 2
func(0x1234U); // calls 1
func(0x1234_u); // calls 2
// also
inline std::int16_t operator "" _s(unsigned long long value)
{
return static_cast<std::int16_t>(value);
}
Even the writers of the C99 standard got caught out by this. This is a snippet from Danny Smith's public domain stdint.h implementation:
/* 7.18.4.1 Macros for minimum-width integer constants
Accoding to Douglas Gwyn <gwyn#arl.mil>:
"This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC
9899:1999 as initially published, the expansion was required
to be an integer constant of precisely matching type, which
is impossible to accomplish for the shorter types on most
platforms, because C99 provides no standard way to designate
an integer constant with width less than that of type int.
TC1 changed this to require just an integer constant
*expression* with *promoted* type."
*/
Disclaimer: I'm leaving this answer up as a curiosity, but you really shouldn't be using this in production code. Use UDL or constants of the appropriate types instead.
If you use Microsoft Visual C++, there are literal suffixes available for every integer type:
auto var1 = 10i8; // char
auto var2 = 10ui8; // unsigned char
auto var3 = 10i16; // short
auto var4 = 10ui16; // unsigned short
auto var5 = 10i32; // int
auto var6 = 10ui32; // unsigned int
auto var7 = 10i64; // long long
auto var8 = 10ui64; // unsigned long long
Note that these are a non-standard extension and aren't portable. In fact, I couldn't even locate any info on these suffixes on MSDN.
You can also use pseudo constructor syntax.
short(2)
I find it more readable than casting.
One possibility is to use C++11 "list initialization" for this purpose, e.g.:
short{42};
The advantage of this solution (compared to a cast as in the currently accepted answer) is that it does not allow narrowing conversions:
auto number1 = short(100000); // Oops: Stores -31072, you may get a warning
auto number2 = short{100000}; // Compiler error. Value too large for type short
See https://en.cppreference.com/w/cpp/language/list_initialization#Narrowing_conversions for prohibited narrowing conversions with list-init
As far as I know, you don't, there's no such suffix. Most compilers will warn if an integer literal is too large to fit in whatever variable you're trying to store it in, though.
Related
Basically an integer variable should allow only integer values to be set for its variable. Then how come such special words as follows are allowed?
int a = 200L;
int a = 200U;
int a = 200F;
I found this when i run the program, it ran perfectly without giving any error. Other letters are not allowed as expected. But why these?
L, U and F means long, unsigned and float respectively.
so, the code means
int a = (long) 200;
int a = (unsigned) 200;
int a = (float) 200;
What you do is called implicit conversion.
If you are using gcc compiler you can add
-Wconversion
(not part of -Wall) option to check any implicit conversion that may alter the value.
Without any option, conversion from signed to unsigned is not warned by default. So you need to active
-Wsign-conversion
If you want an explicit conversion, it will not be warned by those 2 options.
int percent = (int)((int)4.1)*.5;
Two different things are going on here.
1) Some letters when stuck on the end of a number take on meaning. 'l' is for long, 'u' is for unsigned, and 'f' is for float.
"Long" is generally 64 bits wide vs int's 32 bits... but that can
vary wildly from machine to machine. DO NOT depend on bit width of
int and long.
"Unsigned" means it doesn't bother to track positive or
negative values... assuming everything is positive. This about
doubles how high an integer can go. Look up "two's complement" for
further information.
"Float" means "floating point". Non whole numbers. 1.5, 3.1415, etc. They can be very large, or very precise, but not both. Floats ARE 32 bits. "Double" is a 64-bit floating point value, which can permit some extreme values of size or precision.
2) Type Coercion, pronounced "co ER shun".
The compiler knows how to convert (coerce) from long to int, unsigned to int, or float to int. They're all just numbers, right? Note that converting from float to into "truncates" (drops) anything after a decimal place. ((int)3.00000001) == 3. ((int)2.9999999) == 2
If you dial your warnings up to max sensitivity, I believe those statements will all trigger warnings because all those conversions could potentially lose data... though the exact phrasing of that warning will vary from compiler to compiler.
Bonus Information:
You can trigger this same behavior (accidentally) with classes.
struct Foo {
Foo(int bar) {...}
};
Foo baz = 42;
The compiler will treat the above constructor as an option when looking to convert from int to Foo. The compiler is willing to hop through more than one hoop to get there... so Foo qux = 3.14159; would also compile. This is also true of other class constructors... so if you have some other class that takes a foo as it's only constructor param, you can declare a variable of that class and assign it something that can be coerced to a foo... and so on:
struct Corge {
Corge(Foo foo) {...}
};
corge grault = 1.2345; // you almost certainly didn't intend what will happen here
That's three layers of coercion. double to int, into to foo, and foo to corge. Bleh!
You can block this with the explicit keyword:
struct Foo {
explicit Foo(int bar) {...}
};
Foo baz = 1; // won't compile
I wish they'd made explicit the default and used some keyword to define conversion constructors instead, but that change would almost certainly break someone's code, so it'll never happen.
What happens is that you are telling the compiler to convert the value into a different type of data. That is to say:
int a = 200L; // It's like saying: Hey C++, convert this whole to Long
int a = 200U; // And this to Unsigned
int a = 200F; // And this one to Float
There is no error because the compiler understands that these letters at the end indicate a type of conversion.
Very basic question: how do I write a short literal in C++?
I know the following:
2 is an int
2U is an unsigned int
2L is a long
2LL is a long long
2.0f is a float
2.0 is a double
'\2' is a char.
But how would I write a short literal? I tried 2S but that gives a compiler warning.
((short)2)
Yeah, it's not strictly a short literal, more of a casted-int, but the behaviour is the same and I think there isn't a direct way of doing it.
That's what I've been doing because I couldn't find anything about it. I would guess that the compiler would be smart enough to compile this as if it's a short literal (i.e. it wouldn't actually allocate an int and then cast it every time).
The following illustrates how much you should worry about this:
a = 2L;
b = 2.0;
c = (short)2;
d = '\2';
Compile -> disassemble ->
movl $2, _a
movl $2, _b
movl $2, _c
movl $2, _d
C++11 gives you pretty close to what you want. (Search for "user-defined literals" to learn more.)
#include <cstdint>
inline std::uint16_t operator "" _u(unsigned long long value)
{
return static_cast<std::uint16_t>(value);
}
void func(std::uint32_t value); // 1
void func(std::uint16_t value); // 2
func(0x1234U); // calls 1
func(0x1234_u); // calls 2
// also
inline std::int16_t operator "" _s(unsigned long long value)
{
return static_cast<std::int16_t>(value);
}
Even the writers of the C99 standard got caught out by this. This is a snippet from Danny Smith's public domain stdint.h implementation:
/* 7.18.4.1 Macros for minimum-width integer constants
Accoding to Douglas Gwyn <gwyn#arl.mil>:
"This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC
9899:1999 as initially published, the expansion was required
to be an integer constant of precisely matching type, which
is impossible to accomplish for the shorter types on most
platforms, because C99 provides no standard way to designate
an integer constant with width less than that of type int.
TC1 changed this to require just an integer constant
*expression* with *promoted* type."
*/
Disclaimer: I'm leaving this answer up as a curiosity, but you really shouldn't be using this in production code. Use UDL or constants of the appropriate types instead.
If you use Microsoft Visual C++, there are literal suffixes available for every integer type:
auto var1 = 10i8; // char
auto var2 = 10ui8; // unsigned char
auto var3 = 10i16; // short
auto var4 = 10ui16; // unsigned short
auto var5 = 10i32; // int
auto var6 = 10ui32; // unsigned int
auto var7 = 10i64; // long long
auto var8 = 10ui64; // unsigned long long
Note that these are a non-standard extension and aren't portable. In fact, I couldn't even locate any info on these suffixes on MSDN.
You can also use pseudo constructor syntax.
short(2)
I find it more readable than casting.
One possibility is to use C++11 "list initialization" for this purpose, e.g.:
short{42};
The advantage of this solution (compared to a cast as in the currently accepted answer) is that it does not allow narrowing conversions:
auto number1 = short(100000); // Oops: Stores -31072, you may get a warning
auto number2 = short{100000}; // Compiler error. Value too large for type short
See https://en.cppreference.com/w/cpp/language/list_initialization#Narrowing_conversions for prohibited narrowing conversions with list-init
As far as I know, you don't, there's no such suffix. Most compilers will warn if an integer literal is too large to fit in whatever variable you're trying to store it in, though.
I'd like to assign a value to a variable like this:
double var = 0xFFFFFFFF;
As a result var gets the value 65535.0 assigned. Since the compiler assumes a 64bit target system the number literal (i.e. all respective 32 bits) is interpreted significand precision bits. However, since 0xFFFF FFFF is just a notation for a bit pattern, without any hint about the representation, it could be quite differently interpreted w.r.t. becoming a floating point value. Thus, I was wondering if there is a way to manipulate this fixed interpretation of the value. In other words, give a hint about the desired representation. (Maybe someone could also point me to part in the standard where this implicit interpretation is defined).
So far, the default precision interpretation on my system seems to be
(int)0xFFFFFFFF x 100.
Only the fraction field is getting filled1.
So maybe (here: for 16 bit cross-compilation) I want it to be a different representation like:
(int)0xFFFFFF x 10(int)0xFF
(ignoring the sign bit for a moment).
Thus my question: How can I force a custom double interpretation of the hex literal notation?
1 Even when my hex literal would be 0xFFFF FFFF FFFF FFFF the value is only interpreted as the fraction part - so clearly, bits should be used for exponent and sign field. But it seems the literal gets just cut off.
C++ doesn't specify the in-memory representation for double, moreover, it doesn't even specify the in-memory representation of integer types (and it can really be different on systems with different endings). So if you want to interpret bytes 0xFF, 0xFF as a double, you can do something like:
uint8_t bytes[sizeof(double)] = {0xFF, 0xFF};
double var;
memcpy(&var, bytes, sizeof(double));
Note that using unions or reinterpret_casting pointers is, strictly speaking, undefined behavior, though in practice also works.
"I was wondering if there is a way to manipulate this interpretation."
Yes, you can use a reinterpret_cast<double&> via address, to force type (re-)interpretation from a certain bit pattern in memory.
"Thus my question: How can I force double interpretation of the hex notation?"
You can also use a union, to make it clearer:
union uint64_2_double {
uint64_t bits;
double dValue;
};
uint64_2_double x;
x.bits = 0x000000000000FFFF;
std::cout << x.dValue << std::endl;
There does not seem to be a direct way to initialize a double variable with an hexadecimal pattern, the c-style cast is equivalent to a C++ static_cast and the reinterpret_cast will complain it can't perform the conversion. I will give you two options, one simple solution but that will not initialize directly the variable, and a complicated one. You can do the following:
double var;
*reinterpret_cast<long *>(&var) = 0xFFFF;
Note: watch out that I would expect you to want to initialize all 64 bits of the double, your constant 0xFFFF seems small, it gives 3.23786e-319
A literal value that begins with 0x is an hexadecimal number of type unsigned int. You should use the suffix ul to make it a literal of unsigned long, which in most architectures will mean a 64 bit unsigned; or, #include <stdint.h> and do for example uint64_t(0xABCDFE13)
Now for the complicated stuff: In old C++ you can program a function that converts the integral constant to a double, but it won't be constexpr.
In constexpr functions you can't make reinterpret_cast. Then, your only choice to make a constexpr converter to double is to use an union in the middle, for example:
struct longOrDouble {
union {
unsigned long asLong;
double asDouble;
};
constexpr longOrDouble(unsigned long v) noexcept: asLong(v) {}
};
constexpr double toDouble(long v) { return longOrDouble(v).asDouble; }
This is a bit complicated, but this answers your question. Now, you can write:
double var = toDouble(0xFFFF)
And this will insert the given binary pattern into the double.
Using union to write to one member and read from another is undefined behavior in C++, there is an excellent question and excellent answers on this right here:
Accessing inactive union member and undefined behavior?
I see the
#define NUM_MAX_VOLUME 0ui64
in other people's code
What is the number 0ui64? It seems it is not a hex number though.
I am surpsised that there are many answers, but none has pointed out the official and authoritative documentation that should be noted in my opinion, so here goes the MSDN documentation:
unsigned-suffix: one of
u U
and
64-bit integer-suffix:
i64 LL ll
So, it is indeed not a hexa number, but basically a macro define to zero that represents an unsiged 64 bit integer number. Please note that 0Ui64, 0ULL, 0ull, etc, would be all the same, too.
This is necessary when you want to make sure that the sign and size are fixed so that it cannot go unexpected or undefined behavior.
This is neither standard C++, nor C, but a Microsoft compiler feature. Try to avoid it.
Since your question is tagged as Qt, the recommendation is to use quint64 and Q_UINT64_C instead which will work cross-platform. So, you would write something like this:
#define NUM_MAX_VOLUME Q_UINT64_C(0)
"ui64" means unsigned 64-bit integer. It is a non-standard suffix in some cases.
"0ui64" is just 0, and i guess the reason to write like this is for compatibility.
It's basically used in a expression where the size of the operand (the constant here) matters. Take shifting for example:
auto i = 1 << 36;
On a machine where int is 32-bits long this will lead to undefined behaviour. Since the 1 here is taken as an int, and you're trying to shift it beyond the size of the resulting type: int. What you want is a 64-bit integral type, say unsigned long long then you'd do
auto i = 1ULL << 36;
This isn't UB since the resulting type would also be an unsigned long long due to the operand (which is now an unsigned long long too).
Another example is type deduction of the C++11's auto keyword. Try this:
for (auto i = 0; i < v.size(); ++i)
With warnings enabled GCC barks (live example)
warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
However, changing this to
for (auto i = 0u; i < v.size(); ++i)
make the warning disappear. Again since the suffix 0u led the compiler to deduce the type of i as unsigned int and not simply int.
In your case, you've the suffix ui64 which isn't standard C++, so it should be an implementation-specific extension that denotes unsigned 64-bit integer.
0xFull ,for example, is also valid C++ constant. It is 0xF, unsigned long long, a.k.a. ui64 in Microsoft compilers transcription.
This is in C, but I tagged it C++ incase it's the same. This is being built with:
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.220 for 80x86
if that makes any different
Why does this work?
(inVal is 0x80)
float flt = (float) inVal;
outVal = *((unsigned long*)&flt);
(results in outVal being 0x43000000 -- correct)
But this doesn't?
outVal = *((unsigned long*)&((float)inVal));
(results in outVal being 0x00000080 -- NOT CORRECT :( )
Before asking this question I googled around a bit and found this function in java that basically does what I want. If you're a bit confused about what I'm trying to do, this program might help explain it:
class hello
{
public static void main(String[] args)
{
int inside = Float.floatToIntBits(128.0f);
System.out.printf("0x%08X", inside);
}
}
You're trying to take the address of a non-const temporary (the result of your (float) conversion) – this is illegal in C++ (and probably also in C). Hence, your code results in garbage.
In your first, working, code, you're not using a temporary so your code is working. Notice that from a standards point of view this is still ill-defined since the size and internal representation of the involved types isn't specified and may differ depending on platform and compiler. You're probably safe, though.
In C99, you may use compound literals to make this work inline:
unsigned long outVal = *((unsigned long *)&((float){ inVal }));
The literal (float){ inVal } will create a variable with automatic storage duration (ie stack-allocated) with a well-defined address.
Type punning may also be done using unions instead of pointer casts. Using compound literals and the non-standard __typeof__ operator, you can even do some macro magic:
#define wicked_cast(TYPE, VALUE) \
(((union { __typeof__(VALUE) src; TYPE dest; }){ .src = VALUE }).dest)
unsigned long outVal = wicked_cast(unsigned long, (float)inVal);
GCC prefers unions over pointer casts in regard to optimization. This might not work at all with the MS compiler as its C99 support is rumored to be non-existant.
Assuming: inVal and outVal are parameters.
void func(int inVal,unsigned long* outVal)
{
float flt = (float) inVal;
*outVal = (unsigned long)flt; // convert flot to unsigned long.
// Then assign to the variable by de-ref
// the pointer.
}