1

I would copy a uint8_t array in a char array. I tried different solutions with: cast, memcopy, strcpy... but it does not work!!! My little example is:

uint32_t num = 123456789;
printf("\n num: %"PRIu32 "\n", num);
uint32_t x;
uint8_t a[4];
char b[4];

num=htonl(num);

a[0]=num;
a[1]=num>>8;
a[2]=num>>16;
a[3]=num>>24;

b[0] = a[0];
b[1] = a[1];
b[2] = a[2];
b[3] = a[3];



printf("\nA: %x %x %x %x", a[0],a[1],a[2],a[3]);
printf("\nB: %x %x %x %x", b[0],b[1],b[2],b[3]);


x= b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24;

x=ntohl(x);
printf("\n x vale: %"PRIu32 "\n", x);
}

The prints are:

num: 123456789
A: 7 5b cd 15
B: 7 5b ffffffcd 15
x: 123457023

Why I get a differente number in x?

GWW
  • 43,129
  • 11
  • 115
  • 108
Peppifg
  • 35
  • 1
  • 8

2 Answers2

0

You have to modify your code a little to be sure to handle some undefined behavior, such as signed int value overflow.

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <arpa/inet.h>

int main()
{
    uint32_t num = 123456789;
    printf("\n num: %" PRIu32 "\n", num);
    uint32_t x;
    uint8_t a[4];
    unsigned char b[4];

    num=htonl(num);

    a[0] = num & 0x000000FFu;
    a[1] = (num & 0x0000FF00u) >> 8;
    a[2] = (num & 0x00FF0000u) >>16;
    a[3] = (num & 0xFF000000u) >>24;

    b[0] = a[0];
    b[1] = a[1];
    b[2] = a[2];
    b[3] = a[3];


    printf("\nA: %x %x %x %x", a[0],a[1],a[2],a[3]);
    printf("\nB: %x %x %x %x", b[0], b[1], b[2], b[3]);


    x = b[0] | (b[1] & 0x000000FFu)<<8 | (b[2] & 0x000000FFu)<<16 | (b[3] & 0x000000FFu)<<24;

    x = ntohl(x);

    printf("\n x vale: %" PRIu32 "\n", x);

    return 0;
}

As you can see:

  1. b array is declared as unsigned char to avoid undefined behavior. It also correct values printed by 3rd printf in your code.
  2. Inserting value into a array it is more clear if you mask bits you want to move before shift them in the correct position.
  3. When you calculate x value you are performing left shift on 8 bit variables. So you are loosing all bits after 8 shift. &ing them with a 32 bit HEX literal you can be sure to use the correct size for bit shift and for ors

About point 3, as @2501 pointed out, you must use u for literals to be sure to avoid UB on platform where int has a size smaller than 32 bts or where signed int has trap values. See 6.4.4.1. p5 of standard.

Community
  • 1
  • 1
LPs
  • 16,045
  • 8
  • 30
  • 61
  • 1
    If the width of int is less than 32 bits or if signed integer representation has some trap values, then this code has ub when the left shifts are made due to integer promotions. – 2501 May 30 '16 at 15:44
  • @2501 Well, yes, but I though It is too complicate to wrote that well understandable for OP level. BTW My comment was enough. I cancel my inaccurate answer. – LPs May 30 '16 at 15:55
  • Well the solution is really simple just use an unsigned version of: `0x000000FFu` – 2501 May 30 '16 at 15:56
  • @2501 Weird, Aren't hex literals always unsigned? – LPs May 30 '16 at 16:01
  • 1
    Not If they fit into an `int`. See 6.4.4.1. p5 – 2501 May 30 '16 at 16:06
  • @2501 I got it now. I'm a moron and I really need to go to sleep ;) – LPs May 30 '16 at 16:09
  • You can also shift then mask, e.g. `a[1] = (num >> 8) & 0xFF;`, your choice. – David C. Rankin May 30 '16 at 19:27
  • @DavidC.Rankin Yes, sure. For me it is more clear to mask and shift. So at first look I see which bits are affected by the formula. – LPs May 31 '16 at 06:09
0

I don't see why a call to memcpy should not work. Simply check for CHAR_BIT == 8 to be sure char is defined as an 8 bit type (some implemetations define char to be 16 Bit big) and then call memcpy(b, a, sizeof(b) / sizeof(b[0])). This should to the trick. Don't forget to include string.h for memcpy and limits.h for CHAR_BIT.


As others have pointed out you could still get trouble with this, since the signed-ness of char is implementation defined as well. Therefore you should declare b as unsigned char to prevent undefined behavior.

To be 100% save you should also check that a and b do have the same size so you won't get any runtime errors.

muXXmit2X
  • 2,745
  • 3
  • 17
  • 34