Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read 4 bytes of data from a given char pointer in C


Scenario is that, i wanna read 4 bytes of data from a given pointer which is of type char.
Eg: Consider the following -

int a=0;
char* c; // This will have some address 

What i wanna do is read 4 bytes starting from c (i.e. the address) and assign them in variable a which is an integer.

My Solution:

a = *(int*)c;  // Assembly is LDR    r1, [r6,#0x00]

My Problem:
Above solution works well on some architectures but fails on some. To be specific, in my case, it fails on Arm CortexM0.

If any one has any portable, highly efficient(with minimum assembly) replacement of my solution please share, it would be a great help to me and I thank you for that in advance ;)

Please ask if more info needed.

like image 864
Mrmj Avatar asked Oct 26 '25 14:10

Mrmj


2 Answers

The problem could be because of alignment. Some CPU architectures can't read or write non-byte values on unaligned addresses.

The solution is to make unaligned byte-access instead, which can easily be done with memcpy:

memcpy(&a, c, sizeof a);
like image 150
Some programmer dude Avatar answered Oct 28 '25 04:10

Some programmer dude


There are at many different problems here.

  • Alignment. The char pointer must point at an aligned address if you wish to read an integer at that address.
  • Signedness of char. It is implementation-defined whether char is treated as signed or unsigned. It is therefore a bad type to use for any form of bit/byte manipulation. Instead, use uint8_t.
  • Pointer aliasing. Casting a raw address pointed at by a char* to an int* is undefined behavior as it violates the so-called strict aliasing rule. This could cause your code to get incorrectly optimized by the compiler (particularly gcc). The other way around, from int* to char* would have been fine though.

Endianess is not an issue if the stored integer is already in the same endianess format as that of the current system. If not, you'd have to convert it, but that's quite unrelated to the question here...

Example of a portable, safe solution:

#include <stdint.h>
#include <assert.h>
#include <string.h>

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


int main (void) {

  int x = 123;
  uint8_t* c = (uint8_t*)&x; // point to something that is an int
  assert((uintptr_t)c % _Alignof(uint32_t) == 0); // ensure no misalignment

  uint32_t i;
  memcpy(&i, c, sizeof(i)); // safely copy data without violating strict aliasing

  printf("%"PRIu32, i); // print 123

  return 0;
}
like image 39
Lundin Avatar answered Oct 28 '25 04:10

Lundin