3

I wrote a simple program to test copying bytes from a byte buffer to a structure using memcpy. However I am not getting the results expected.

I allocate a buffer of 100 bytes, and set the values 0, 1, 2...99. I then copy the bytes to a structure that is 16 bytes.

Somewhere byte 0x01 gets lost. I am trying to understand what is happening

#include <stdio.h>
#include <stdint.h>

struct Test {

    uint8_t a;
    uint16_t b;
    uint32_t c;
    uint64_t d;
    uint8_t e;
};

int main(int argc, char** argv) {

    uint8_t buffer[100];
    for (uint8_t i = 0; i < 100; i++) {
        buffer[i] = i;
    }

    struct Test test;
    memcpy(&test, buffer, sizeof(struct Test));

    printf("A is %ld and should be %ld\n", test.a, 0x00);
    printf("B is %ld and should be %ld\n", test.b, 0x0201);
    printf("C is %ld and should be %ld\n", test.c, 0x06050403);
    printf("D is %ld and should be %ld\n", test.d, 0x1413121110090807);
    printf("E is %ld and should be %ld\n", test.e, 0x15);
}

And I get a result of:

A is 0 and should be 0
B is 770 and should be 513
C is 117835012 and should be 100992003
D is 1084818905618843912 and should be 1446519769808832519
E is 16 and should be 21

770 (B value) is bytes 0302, not 0201 (int 513)

user2840470
  • 919
  • 1
  • 11
  • 23

1 Answers1

5

The reason for this is the compiler has added padding to your struct in order to ensure that b is aligned on a 16-bit boundary. As such, the second byte is unused.

You'll see a much bigger variation if you start re-ordering your struct. Similarly, the 32-bit and 64-bit values will want an alignment suitable to their type. So you can end up with significant "holes" due to padding. Try it!

Often you will see structures that have reserved members (particularly for binary formats), instead of relying on padding.

paddy
  • 60,864
  • 6
  • 61
  • 103
  • Ah that makes sense. Rookie mistake. So im guessing the consesus is dont use memcpy to do this type of operation. Better to manually assign each variable (a = buffer[0], b = buffer[2] << 8 | bufer[1]) – user2840470 Oct 30 '19 at 20:49
  • That completely depends on what you're trying to achieve. It's very common to read and write a struct from/to a buffer with `memcpy`. But you must be careful when making assumptions _external_ to the execution environment (_e.g._ hard-coding memory contents in code, or reading from a file) – paddy Oct 30 '19 at 20:53
  • @user2840470 Not necessarily. A common pratical use of *byte streams* memcopied into structs is when you receive network data and payload of N-th level protocol have to be forwarded to (N+1)-th level protocol (for example, IP packet payload is forwarded to TCP). In this cases it's just a design matter: struct are designed to be *packed-data friendly*, and PACK/UNPACK macros are always present in porting layers to manage special cases. So the question is: can your struct be changed in order to be *packed-data friendly*? :) (BTW: +1 for both Q&A. Interesting topic) – Roberto Caboni Oct 30 '19 at 21:09
  • 1
    @Cubo78 That makes sense now why I see structs laid out in certain ways. I can definitely change the order of my struct to better match word boundaries. Thanks for explaining more! – user2840470 Oct 31 '19 at 12:39