Reputation: 125
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.
Upvotes: 4
Views: 12648
Reputation: 213852
There are at many different problems here.
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
.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;
}
Upvotes: 4
Reputation: 409176
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);
Upvotes: 7
Reputation: 50775
If endianness is an issue for you:
Instead of:
a = *(int*)c; // Assembly is LDR r1, [r6,#0x00]
you need this:
On big endian systems:
a = c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3];
On little endian systems:
a = c[3] << 24 | c[2] << 16 | c[1] << 8 | c[0];
// probably faster (only on little endian systems) :
memcpy(&a, c, sizeof a);
Upvotes: 1
Reputation: 16223
Depending on the endianness
#include <stdio.h>
int main(void)
{
unsigned char bytes[] = { 0xAA, 0x55, 0xAA, 0x55 };
unsigned int a=0;
unsigned char* c = bytes;
a += (*c++ & 0xFFFFFFFFu) << 0;
a += (*c++ & 0xFFFFFFFFu) << 8;
a += (*c++ & 0xFFFFFFFFu) << 16;
a += (*c & 0xFFFFFFFFu) << 24;
printf("HEX: %X\n", a);
a = 0;
c = bytes;
a |= (*c++ & 0xFFFFFFFFu) << 24;
a |= (*c++ & 0xFFFFFFFFu) << 16;
a |= (*c++ & 0xFFFFFFFFu) << 8;
a |= (*c & 0xFFFFFFFFu) << 0;
printf("HEX: %X\n", a);
}
Upvotes: 0