Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what is the reason for explicitly declaring L or UL for long values

Tags:

c

constants

From an Example

unsigned long x = 12345678UL 

We have always learnt that the compiler needs to see only "long" in the above example to set 4 bytes (in 32 bit) of memory. The question is why is should we use L/UL in long constants even after declaring it to be a long.

like image 637
Shash Avatar asked Oct 30 '12 08:10

Shash


People also ask

What is U and UL in C?

Unsigned constants are written with a terminal u or U , and the suffix ul or UL indicates unsigned long . Floating-point constants contain a decimal point ( 123.4 ) or an exponent ( 1e-2 ) or both; their type is double , unless suffixed.

What is UL in hexadecimal?

LL designates a literal as a long long and UL designates one as unsigned long and 0x0 is hexadecimal for 0 . So 0LL and 0x0UL are an equivalent number but different datatypes; the former is a long long and the latter is an unsigned long .

How big is unsigned long long?

An unsigned version of the long long data type. An unsigned long long occupies 8 bytes of memory; it stores an integer from 0 to 2^64-1, which is approximately 1.8×10^19 (18 quintillion, or 18 billion billion). A synonym for the unsigned long long type is uint64 .

What is unsigned long in C?

Unsigned long variables are extended size variables for number storage, and store 32 bits (4 bytes). Unlike standard longs unsigned longs won't store negative numbers, making their range from 0 to 4,294,967,295 (2^32 - 1).


2 Answers

When a suffix L or UL is not used, the compiler uses the first type that can contain the constant from a list (see details in C99 standard, clause 6.4.4:5. For a decimal constant, the list is int, long int, long long int).

As a consequence, most of the times, it is not necessary to use the suffix. It does not change the meaning of the program. It does not change the meaning of your example initialization of x for most architectures, although it would if you had chosen a number that could not be represented as a long long. See also codebauer's answer for an example where the U part of the suffix is necessary.


There are a couple of circumstances when the programmer may want to set the type of the constant explicitly. One example is when using a variadic function:

printf("%lld", 1LL); // correct, because 1LL has type long long printf("%lld", 1);   // undefined behavior, because 1 has type int 

A common reason to use a suffix is ensuring that the result of a computation doesn't overflow. Two examples are:

long x = 10000L * 4096L; unsigned long long y = 1ULL << 36; 

In both examples, without suffixes, the constants would have type int and the computation would be made as int. In each example this incurs a risk of overflow. Using the suffixes means that the computation will be done in a larger type instead, which has sufficient range for the result.

As Lightness Races in Orbit puts it, the litteral's suffix comes before the assignment. In the two examples above, simply declaring x as long and y as unsigned long long is not enough to prevent the overflow in the computation of the expressions assigned to them.


Another example is the comparison x < 12U where variable x has type int. Without the U suffix, the compiler types the constant 12 as an int, and the comparison is therefore a comparison of signed ints.

int x = -3; printf("%d\n", x < 12); // prints 1 because it's true that -3 < 12 

With the U suffix, the comparison becomes a comparison of unsigned ints. “Usual arithmetic conversions” mean that -3 is converted to a large unsigned int:

printf("%d\n", x < 12U); // prints 0 because (unsigned int)-3 is large 

In fact, the type of a constant may even change the result of an arithmetic computation, again because of the way “usual arithmetic conversions” work.


Note that, for decimal constants, the list of types suggested by C99 does not contain unsigned long long. In C90, the list ended with the largest standardized unsigned integer type at the time (which was unsigned long). A consequence was that the meaning of some programs was changed by adding the standard type long long to C99: the same constant that was typed as unsigned long in C90 could now be typed as a signed long long instead. I believe this is the reason why in C99, it was decided not to have unsigned long long in the list of types for decimal constants. See this and this blog posts for an example.

like image 172
Pascal Cuoq Avatar answered Oct 17 '22 12:10

Pascal Cuoq


Because numerical literals are of typicaly of type int. The UL/L tells the compiler that they are not of type int, e.g. assuming 32bit int and 64bit long

long i = 0xffff; long j = 0xffffUL; 

Here the values on the right must be converted to signed longs (32bit -> 64bit)

  1. The "0xffff", an int, would converted to a long using sign extension, resulting in a negative value (0xffffffff)
  2. The "0xffffUL", an unsigned long, would be converted to a long, resulting in a positive value (0x0000ffff)
like image 22
codebauer Avatar answered Oct 17 '22 10:10

codebauer