Hoa.N
Hoa.N

Reputation: 463

Failing to understand what the expression *(uint32_t*) does

I am failing to understand what the expression *(uint32_t*) does.

I have broken the statement down to an example that declares the parts so I can try and interpret what each one does.

  uint32_t* ptr;
  uint32_t num
  *(uint32_t*)(ptr + num); // <-- what does this do?

I don't understand the last bit in the example, what happens when the expression *(uint32_t*)(ptr + num); executes during runtime?

Upvotes: 45

Views: 208971

Answers (3)

Pablo
Pablo

Reputation: 13580

uint32_t is a numeric type that guarantees 32 bits. The value is unsigned, meaning that the range of values goes from 0 to 232 - 1.

This

uint32_t* ptr;

declares a pointer of type uint32_t*, but the pointer is uninitialized, that is, the pointer does not point to anywhere in particular. Trying to access memory through that pointer will cause undefined behaviour and your program might crash.

This

uint32_t num;

is just a variable of type uint32_t.

This

*(uint32_t*)(ptr + num);

ptr + num returns you a new pointer. It is called pointer arithmetic. It's like regular arithmetic, only that compiler takes the size of types into consideration. Think of ptr + num as the memory address based on the original ptr pointer plus the number of bytes for num uint32_t objects.

The (uint32_t*) x is a cast. This tells the compiler that it should treat the expression x as if it were a uint32_t*. In this case, it's not even needed, because ptr + num is already a uint32_t*.

The * at the beginning is the dereferencing operator which is used to access the memory through a pointer. The whole expression is equivalent to

ptr[num];

Now, because none of these variables is initialized, the result will be garbage.

However, if you initialize them like this:

uint32_t arr[] = { 1, 3, 5, 7, 9 };
uint32_t *ptr = arr;
uint32_t num = 2;

printf("%u\n", *(ptr + num));

this would print 5, because ptr[2] is 5.

Upvotes: 83

Cole
Cole

Reputation: 751

This type of expression is usually used in type punning. If you're not familiar with type punning, the main idea is to bypass the type system so that you can treat something as a different type than it really is (ie treat an int a as double)

The main idea behind type punning is you take a pointer to a current variable and then pun it into a different type by casting it into a pointer of that type and then dereferencing it, hence the commonly used cast and dereference you are referring to ( *(uint32_t *) = cast to unsigned 32bit int pointer and then dereference).

As others have pointed out, your code "does nothing" because you are punning an int to an int, which has no effect. If you wanted to pun an int into a double however...

uint32_t num=5;
double& myvar=*(double*) &num;

Now you can manipulate nums memory as a double via myvar even though num is still an Int. This is a terrible idea and is just meant as a toy example of the use of punning.

Upvotes: 0

giusti
giusti

Reputation: 3538

This doesn't really do anything. Let me give you a different example:

uint32_t data;
void *pointer = &data;
*(uint32_t *)pointer = 5;

First of all, void* means "generic" pointer. It can point to objects of any type.

Now, (uint32_t *) means "interpret pointer as a pointer to an object with type uint32_t.

The rest of the expression simply means "store 5 at the location stored by this pointer".

If you want to know what uint32_t is, that's an unsigned integer with exactly 32 bits. And pointer + num is the same as the adress of pointer[5].

Upvotes: 3

Related Questions