Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why cast to a pointer then dereference?

Tags:

I was going through this example which has a function outputting a hex bit pattern to represent an arbitrary float.

void ExamineFloat(float fValue)
{
    printf("%08lx\n", *(unsigned long *)&fValue);
}

Why take the address of fValue, cast to unsigned long pointer, then dereference? Isn't all that work just equivalent to a direct cast to unsigned long?

printf("%08lx\n", (unsigned long)fValue);

I tried it and the answer isn't the same, so confused.

like image 718
bobbay Avatar asked Sep 03 '16 23:09

bobbay


People also ask

What is the purpose of dereferencing?

Dereferencing is used to access or manipulate data contained in memory location pointed to by a pointer. *(asterisk) is used with pointer variable when dereferencing the pointer variable, it refers to variable being pointed, so this is called dereferencing of pointers.

What happens when you cast a pointer?

A pointer is an arrow that points to an address in memory, with a label indicating the type of the value. The address indicates where to look and the type indicates what to take. Casting the pointer changes the label on the arrow but not where the arrow points.

What does dereference a pointer mean?

Dereferencing a pointer means getting the value that is stored in the memory location pointed by the pointer. The operator * is used to do this, and is called the dereferencing operator.

Does casting a pointer change its value?

A cast does not change the value of an object. While technically correct, your answer is misleading. Casting a pointer to a class instance may return a different pointer address than the casted pointer contains.


2 Answers

(unsigned long)fValue

This converts the float value to an unsigned long value, according to the "usual arithmetic conversions".

*(unsigned long *)&fValue

The intention here is to take the address at which fValue is stored, pretend that there is not a float but an unsigned long at this address, and to then read that unsigned long. The purpose is to examine the bit pattern which is used to store the float in memory.

As shown, this causes undefined behavior though.

Reason: You may not access an object through a pointer to a type that is not "compatible" to the object's type. "Compatible" types are for example (unsigned) char and every other type, or structures that share the same initial members (speaking of C here). See §6.5/7 N1570 for the detailed (C11) list (Note that my use of "compatible" is different - more broad - than in the referenced text.)

Solution: Cast to unsigned char *, access the individual bytes of the object and assemble an unsigned long out of them:

unsigned long pattern = 0;
unsigned char * access = (unsigned char *)&fValue;
for (size_t i = 0; i < sizeof(float); ++i) {
  pattern |= *access;
  pattern <<= CHAR_BIT;
  ++access;
}

Note that (as @CodesInChaos pointed out) the above treats the floating point value as being stored with its most significant byte first ("big endian"). If your system uses a different byte order for floating point values you'd need to adjust to that (or rearrange the bytes of above unsigned long, whatever's more practical to you).

like image 62
Daniel Jour Avatar answered Oct 24 '22 05:10

Daniel Jour


Floating-point values have memory representations: for example the bytes can represent a floating-point value using IEEE 754.

The first expression *(unsigned long *)&fValue will interpret these bytes as if it was the representation of an unsigned long value. In fact in C standard it results in an undefined behavior (according to the so-called "strict aliasing rule"). In practice, there are issues such as endianness that have to be taken into account.

The second expression (unsigned long)fValue is C standard compliant. It has a precise meaning:

C11 (n1570), § 6.3.1.4 Real floating and integer

When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined.

like image 35
md5 Avatar answered Oct 24 '22 03:10

md5