1

I have seen some codes they use '0x0000FFFFFFFFFFFFLL'. And I have no clue what does it do. Can someone explain me what does this code part do.

int64 l1;
l1 = *(Int64 *)&d1 & 0x0000FFFFFFFFFFFFLL;

Although this is not appropriate for ‘stackoverflow’ I have nowhere to find an answer. I am new for programming, please help.

wicky
  • 384
  • 3
  • 17
  • The integer suffixes are in both C and C++, yes. – Blindy Jan 27 '15 at 06:25
  • possible duplicate of [What do 0LL or 0x0UL mean?](http://stackoverflow.com/questions/7036056/what-do-0ll-or-0x0ul-mean) – phuclv Jan 27 '15 at 06:31
  • 1
    http://stackoverflow.com/questions/8809292/ull-suffix-on-a-numeric-literal http://stackoverflow.com/questions/15575054/what-does-ll-mean http://stackoverflow.com/questions/2958007/what-does-the-l-mean-at-the-end-of-an-integer-literal – phuclv Jan 27 '15 at 06:32
  • @Blindy: Yes, but programs that *use* the integer suffixes are generally in just one language or the other. – ruakh Jan 27 '15 at 06:40
  • What ends up in `l1` kinda depends on what `d1` is. I assume it's a double? – Retired Ninja Jan 27 '15 at 06:44

5 Answers5

7

0x0000FFFFFFFFFFFFLL is a long long int constant in both C and C++, guaranteed to have a certain minimum range of values, for handling larger numbers than you usually get with int or long (a).

In this particular case, it's setting to zero all bits except the right-most 48 (each F is four bits).

As to why it's doing that, it's almost, but not quite (based on the variable names and your mention in a comment that d1 is a double variable) a piece of code that gives you the fractional bits of a double (IEEE754 double precision) variable.

As per the IEEE754-1985 wikipedia page, the 64-bit value is structured thus:

enter image description here

with the top twelve bits being sign and exponent so, if it were 0x000FFFFFFFFFFFFFLL (thirteen F digits rather than twelve), that would probably be the reason. But, unless you've made a mistake typing the value in, it's less likely. Without further context, it will be difficult to be certain what the overall intent (rather than the effect) is.

For a precis of the bitwise operators (such as &, the bitwise AND operator), see this Stack Overflow answer.


(a) Technically (at least for C), it's only required to be at least as "wide" (in terms of bits) as a long (which is, in turn, only required to be at least as wide as an int). They could, in fact be all the same size, keeping in mind the requirement that long long must be able to store numbers in the range +/- 9,223,372,036,854,775,807 (which is 7fffffffffffffff in hexadecimal), so easily able to hold your given constant.

Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
1

LL is the long long suffix, the 64 bit integer modifier. It's just a way to write a literal value and give it a type rather than let the compiler infer it by itself.

Probably useless in your context, as the value doesn't fit in a 32 bit integer anyway.

Blindy
  • 65,249
  • 10
  • 91
  • 131
  • 1
    Blindy, technically, it's at _least_ 64 bits but, more of an issue, I'm not sure I understand your other points. The compiler is not _allowed_ to infer the type (unadorned integer constants are `int`), so I can't see why it's useless in this case. – paxdiablo Jan 27 '15 at 06:41
  • @paxdiablo, If you say so: http://ideone.com/n2xoPk Good thing you downvoted correct answers though. – Blindy Jan 27 '15 at 14:02
  • Blindy, one implementation does not dictate behaviour, the standard does. It specifies minimum ranges of values, not fixed bit widths. And I didn't downvote you, the comment was a chance for you to fix your answer. The fact you chose to accuse me _rather_ than fix it is interesting :-) – paxdiablo Jan 27 '15 at 21:29
  • @paxdiablo, Fix what? I said the suffix is the 64bit integer modifier and it is. If future compilers choose to put it in larger types (they won't) it's up to them, but that's what the suffix is. I also said it's probably useless because any sane compiler will make the value an `int64` anyway, with an example of a compiler that does. – Blindy Jan 28 '15 at 05:06
  • `LL` is _not_ a 64-bit modifier, it's simply an indication that the constant is a `long long int` type, which is _at least_ 64-bits wide (the standard doesn't explicitly state that but the minimum ranges combined with the encoding schemes means that's the case). And thinking that future environments won't have a massive `char` to handle Unicode, along with 64-bit `int`, 128-bit `long` and 1024-bit `long long` makes about as much sense as "640K should be enough for anybody" or "the expected world-wide market for computers is five" :-) – paxdiablo Jan 28 '15 at 05:18
  • Still, I can't _force_ you to address the deficiencies, I may not even be able to convince you that they _are_ deficiencies. You'll have to make the call, but I'd suggest you read the standard before doing so. – paxdiablo Jan 28 '15 at 05:19
1

This mask used with anding operation (&) will zero out proper bits. And operator works in following manner:

A  B  result
0  0    0
0  1    0
1  0    0
1  1    1

In that context, 16 most significant bits will be ignored (because of 0x0000) and the rest will hold the value from another variable (in your case it is d1).

Speaking of d1 variable, if we would know what is its type and value we would be able to deduce what is the result of masking you are asking about (oh, and an endianness of your machine).

macfij
  • 3,093
  • 1
  • 19
  • 24
1

Literal constants have a type, just like variables. By default, integer literals are of type int. However, certain suffixes may be appended to an integer literal to specify a different integer type:

Suffix     Type modifier
u or U     unsigned
l or L     long
ll or LL   long long
f or F     float
l or L     long double

Unsigned may be combined with any of the other two in any order to form unsigned long or unsigned long long.

In all the cases above, the suffix can be specified using either upper or lowercase letters.

For character types( char ). A different character type can be specified by using one of the following prefixes:

Prefix  Character type
u       char16_t
U       char32_t
L       wchar_t

For example:

75         // int
75u        // unsigned int
75l        // long
75ul       // unsigned long 
75lu       // unsigned long 
75ULL      // unsigned long long
3.14159L   // long double
6.02e23f   // float  

Note that, unlike type suffixes for integer literals, these prefixes are case sensitive: lowercase for char16_t and uppercase for char32_t and wchar_t.

For string literals, apart from the above u, U, and L, two additional prefixes exist:

Prefix  Description
u8      The string literal is encoded in the executable using UTF-8
R       The string literal is a raw string

In raw strings, backslashes and single and double quotes are all valid characters; the content of the literal is delimited by an initial R"sequence( and a final )sequence", where sequence is any sequence of characters (including an empty sequence). The content of the string is what lies inside the parenthesis, ignoring the delimiting sequence itself. For example:

R"(string with \backslash)"
R"&%$(string with \backslash)&%$"

Both strings above are equivalent to "string with \backslash". The R prefix can be combined with any other prefixes, such as u, L or u8.

Sridhar Nagarajan
  • 1,085
  • 6
  • 14
0

Operator precedence is quite important here, puzzling me about the question:

l1 = *(Int64 *)&d1 & 0x0000FFFFFFFFFFFFLL;

The first '&' is the 'address of', the second is the 'bitwise and'.

As the layout suggests, the term *(Int64 *)&d1 is evaluated first, yielding the value of d1 as a 64 bit int. Of that value the bits are and' with the long long literal.

However, I could be wrong and the "layout suggestion" often plays tricks. Better to explicitly bracket the expression(s):

l1 = (*(Int64 *)&d1) & 0x0000FFFFFFFFFFFFLL;

Q: why write *(Int64 *)&d1 and not simply (Int64)d1?? So it seems this expession brings more questions than the answers so far addressed.

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
  • Paul: re your question at the end, there's a difference between casting a _value_ from one type to another (which will try to preserve the value) and treating an address as if it contained a different type. Example, `double x = 1000; printf ("%d\n", (int)x); printf ("%d\n", *((int*)(&x)));` may give different results. – paxdiablo Jan 28 '15 at 05:40