2

Is this a safe way to convert array to number?

// 23 FD 15 94 -> 603788692
char number[4] = {0x94, 0x15, 0xFD, 0x23};
uint32_t* n = (uint32_t*)number;
printf("number is %lu", *n);

MORE INFO

I'm using that in a embedded device with LSB architecture, does not need to be portable. I'm currently using shifting, but if this code is safe i prefer it.

2
  • No..safe and better is char* n = number; Commented Oct 5, 2013 at 11:27
  • 2
    It depends on the endianness, also you could have alingment issues. and ..._t types have special printf formatters. Commented Oct 5, 2013 at 11:28

3 Answers 3

3

No. You're only allowed to access something as an integer if it is an integer.

But here's how you can manipulate the binary representation of an object by simply turning the logic around:

uint32_t n;

unsigned char * p = (unsigned char *)&n;

assert(sizeof n == 4);    // assumes CHAR_BIT == 8

p[0] = 0x94; p[1] = 0x15; p[2] = 0xFD; p[3] = 0x23;

The moral: You can treat every object as a sequence of bytes, but you can't treat an arbitrary sequence of bytes as any particular object.

Moreover, the binary representation of a type is very much platform dependent, so there's no telling what actual integer value you get out from this. If you just want to synthesize an integral value from its base-256 digits, use normal maths:

uint32_t n = 0x94 + (0x15 * 0x100) + (0xFD * 0x10000) + (0x23 * 0x1000000);

This is completely platform-independent and expresses what you want purely in terms of values, not representations. Leave it to your compiler to produce a machine representation of the code.

Sign up to request clarification or add additional context in comments.

6 Comments

@willus: Define "works" :-) I've added what I think is the "real" solution to the OP's problem.
@willus: the OP assured us s/he's on an LSB architecture. Even n[0] + (n[1]<<8) +.. makes an assumption on endianness.
The OP lists the expected result in the top comment line. That result assumes LSB architecture if byte placement is used, but will always be achieved if bit shifting is used.
this uint32_t n = 0x94 + (0x15 * 0x100) + (0xFD * 0x10000) + (0x23 * 0x1000000); does not works, it returns to me 22FD1494
No sorry it works the problema was the sign: uint32_t n1 = (uint32_t)number[0] + (uint32_t)((unsigned char)number[1])*0x100 + (uint32_t)((unsigned char)number[2])*0x10000 + (uint32_t)((unsigned char)number[3])*0x1000000;
|
3

No, it is not safe.

This is violating C aliasing rules that say that an object can only be accessed trough its own type, its signed / unsigned variant or through a character type. It can also invoke undefined behavior by breaking alignment.

A safe solution to get a uint32_t value from the array is to use bitwise operators (<< and &) on the char values to form an uint32_t.

3 Comments

and safe is char* n = number; :)
I tried to get a warning with gcc (-Wstrict-aliasing -fstrict-aliasing), but it doesn't report anything. Is there a way to catch this?
@KarolyHorvath on my system gcc gives me the aliasing warning with -Wstrict-aliasing=2. Anyway -Wstrict-aliasing is best-effort and is not guaranteed to catch all aliasing breaks.
0

You're better off with something like this (more portable):

int n = (c[3]<<24)|(c[2]<<16)|(c[1]<<8)|c[0];

where c is an unsigned char array.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.