Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

232
Visualizações
Pad a packed struct in C for 32-bit alignment

I have a struct defined that is used for messages sent across two different interfaces. One of them requires 32-bit alignment, but I need to minimize the space they take. Essentially I'm trying to byte-pack the structs, i.e. #pragma pack(1) but ensure that the resulting struct is a multiple of 32-bits long. I'm using a gcc arm cross-compiler for a 32-bit M3 processor. What I think I want to do is something like this:

#pragma pack(1)
typedef struct my_type_t
{
    uint32_t someVal;
    uint8_t anotherVal;
    uint8_t reserved[<??>];
}
#pragma pack()

where <??> ensures that the size of my_type_t is divisible by 4 bytes, but without hard-coding the padding size. I can do something like this:

#pragma pack(1)
typedef struct wrapper_t
{
    my_type_t m;
    uint8_t reserved[sizeof(my_type_t) + 4 - (sizeof(my_type_t) % 4)]
}
#pragma pack()

but I'd like to avoid that.

Ultimately what I need to do is copy this to a buffer that is 32-bit addressable, like:

static my_type_t t; //If it makes a difference, this will be declared statically in my C source file
...
memcpy(bufferPtr, (uint32_t*)&t, sizeof(t)) //or however I should do this

I've looked at the __attribute__((align(N))) attribute, which gives me the 32-bit aligned memory address for the struct, but it does not byte-pack it. I am confused about how (or if) this can be combined with pack(1).

My question is this:

What is the right way to declare these structs so that I can minimize their footprint in memory but that allows me to copy/set it in 4-byte increments with a unsigned 32-bit pointer? (There are a bunch of these types of arbitrary size and content). If my approach above of combining pack and padding is going about this totally wrong, I'll happily take alternatives.

Edit:

Some constraints: I do not have control over one of the interfaces. It is expecting byte-packed frames. The other side is 32-bit addressable memory mapped registers. I have 64k of memory for the entire executable, and I'm limited on the libraries etc. I can bring in. There is already a great deal of space optimization I've had to do.

The struct in this question was just to explain my question. I have numerous messages of varying content that this applies to.

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

I can't speak for the specific compiler and architecture you are using, but I would expect the following to be sufficient:

typedef struct {
   uint32_t x;
   uint8_t  y;
} my_type_t;

The structure normally has the same alignment as its largest field, and that includes adding the necessary padding at the end.

my_type_t
+---------------+
| x             |
+---+-----------+
| y | [padding] |
+---+-----------+

|<-- 32 bits -->|

Demo

This is done so the fields are properly aligned when you have an array of them.

my_type_t my_array[2];

my_array[1].x = 123;  // Needs to be properly aligned.

The above assumes you have control over the order of the fields to get the best space efficiency, because it relies on the compiler aligning the individual fields. But those assumptions can be removed using GCC attributes.

typedef struct {
   uint8_t  x;
   uint32_t y;
   uint8_t  z;
}
   __attribute__((packed))      // Remove interfield padding.
   __attribute__((aligned(4)))  // Set alignment and add tail padding.
   my_type_t;

This produces this:

my_type_t
+---+-----------+
| x | y         
+---+---+-------+
    | z | [pad] |
+---+---+-------+

|<-- 32 bits -->|

Demo

The packed attribute prevents padding from being added between fields, but aligning the structure to a 32-bit boundary forces the alignment you desire. This has the side effect of adding trailing padding so you can safely have an array of these structures.

over 4 years ago · Santiago Trujillo Relatório

0

As you use gcc you need to use one of the attributes.

Example + demo.

#define PACKED __attribute__((packed))
#define ALIGN(n) __attribute__((aligned(n)))

typedef struct 
{
    uint8_t anotherVal;
    uint32_t someVal;
}PACKED my_type_t;


my_type_t t = {1, 5};
ALIGN(64) my_type_t t1 = {1, 5};
ALIGN(512) my_type_t t2 = {2, 6};

int main()
{
    printf("%p, %p, %p", (void *)&t, (void *)&t1, (void *)&t2);
}

Result:

0x404400, 0x404440, 0x404600

https://godbolt.org/z/j9YjqzEYW

over 4 years ago · Santiago Trujillo Relatório

0

I suggest combining #pragma pack with alignas:

#include <stdalign.h>
#include <stdint.h>

typedef struct {
    #pragma pack(1)
    alignas(4) struct {      // requires 2+1+2 bytes but is aligned to even 4:s
        uint16_t someVal;    // +0
        uint8_t anotherVal;  // +2
        uint16_t foo;        // +3 (would be 4 without packing)
    };
    #pragma pack()
} my_type_t;

The anonymous inside struct makes access easy as before:

int main() {
    my_type_t y;
    y.someVal = 10;
    y.anotherVal = 'a';
    y.foo = 20;

    printf("%zu\n", (char*)&y.someVal - (char*)&y.someVal);    // 0
    printf("%zu\n", (char*)&y.anotherVal - (char*)&y.someVal); // 2
    printf("%zu\n", (char*)&y.foo - (char*)&y.someVal);        // 3

    my_type_t x[2];
    printf("%zu\n", (char*)&x[1] - (char*)&x[0]); // 8 bytes diff
}

If you'd like to be able to take the sizeof the actual data carrying part of my_type_t (to send it), you could name the inner struct (which makes accessing the fields a little more cumbersome):

#pragma pack(1)
typedef struct {
    uint16_t someVal;
    uint8_t anotherVal;
    uint16_t foo;
} inner;
#pragma pack()

typedef struct {
    alignas(4) inner i;
} my_type_t;

You'd now have to mention i to access the fields, but it has the benefit that you can take sizeof and get 5 (in this example):

int main() {
    my_type_t y;

    printf("%zu %zu\n", sizeof y, alignof(y));   // 8 4
    printf("%zu\n", sizeof y.i);                 // 5    (the actual data)
}
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda