Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C pointer conversions

Tags:

c

pointers

Let's suppose I have a buffer of bytes:

char buffer[] = {  0x11, 0x00, 0x00, 0x02, .... };

What I want to do is to take a qword from a specific offset. The offset will be calculated in bytes. Here is what I have done:

unsigned long long *ptr = &buffer[16];
unsigned long long myqword = *ptr;

It seems to works for me. I am skipping 16 bytes from the beginning and then taking 8 bytes.

My question is why do I get this warning message:

warning: initialization of ‘long long unsigned int *’ from incompatible pointer type ‘char *’ [-Wincompatible-pointer-types]
   unsigned long long *ptr = &buffer[16];
like image 888
Bob5421 Avatar asked Jan 28 '23 10:01

Bob5421


1 Answers

There's 4 major problems here:

  • unsigned long long* is not compatible with char*. This is the cause for the compiler error.
  • Reading a bunch of char through a unsigned long long* would violate the strict aliasing rule, invoking undefined behavior bugs.
  • Reading a bunch of char through a unsigned long long* may also cause misaligned access, invoking undefined behavior bugs.
  • Using char to store integer values is a very bad idea, since char has implementation-defined signedness and could be signed on some computers. Use uint8_t instead.

What you should do instead is to use memcpy:

size_t n = sizeof(unsigned long long);
memcpy(&myqword, &buffer[i * n], n);

If you actually need to access the contents of a specific memory location without copying it, you have no other option but to make some new type, like a union:

#include <inttypes.h>
#include <stdio.h>

typedef union
{
  uint8_t  byte [8];
  uint64_t qword;
} qword_t;

int main (void)
{
  qword_t q = {.byte = {0x11, 0x00, ...} };
  printf("%"PRIu64, q.qword);
}

But please note that this code depends on CPU endianess and is non-portable.

like image 189
Lundin Avatar answered Jan 30 '23 04:01

Lundin