Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

391
Vistas
C vs C++ placing structs in unsigned char buffer

Does C have anything similar to C++ where one can place structs in an unsigned char buffer as is done in C++ as shown in the standard sec. 6.7.2

template<typename ...T>
struct AlignedUnion {
  alignas(T...) unsigned char data[max(sizeof(T)...)];
};
int f() {
  AlignedUnion<int, char> au;
  int *p = new (au.data) int;           // OK, au.data provides storage
  char *c = new (au.data) char();       // OK, ends lifetime of *p
  char *d = new (au.data + 1) char();
  return *c + *d;                       // OK
}

In C I can certainly memcpy a struct of things(or int as shown above) into an unsigned char buffer, but then using a pointer to this struct one runs into strict aliasing violations; the buffer has different declared type.

So suppose one would want to replicate the second line in f the C++ above in C. One would do something like this

#include<string.h>
#include<stdio.h>
struct Buffer {
  unsigned char data[sizeof(int)];
};

int main()
{ 
  struct Buffer b;
  int n = 5;
  int* p = memcpy(&b.data,&n,sizeof(int));
  printf("%d",*p);  // aliasing violation here as unsigned char is accessed as int
  return 0;
}

Unions are often suggested i.e. union Buffer {int i;unsigned char b[sizeof(int)]}; but this is not quite as nice if the aim of the buffer is to act as storage (i.e. placing different sized types in there, by advancing a pointer into the buffer to the free part + potenially some more for proper alignment).

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Have you tried using a union?

#include <string.h>
#include <stdio.h>

union Buffer {
    int int_;
    double double_;
    long double long_double_;
    unsigned char data[1];
};

int main() {
    union Buffer b;
    int n = 5;
    int *p = memcpy(&b.data, &n, sizeof(int));
    printf("%d", *p);  // aliasing violation here as unsigned char is accessed as int
    return 0;
}

The Buffer aligns data member according the type with the greatest alignment requirement.

over 4 years ago · Santiago Trujillo Denunciar

0

Yes, because of strict aliasing rule it is just not possible. As it is not possible to write a standard compliant malloc().

Your buffer is not aligned - alignas(int) from stdalign.h needs to be added.

If you want to protect against compiler optimizations, either:

  • just cast the pointer and access it and compile with -fno-strict-aliasing, or use volatile
  • or move the accessor to the buffer to another file that is compiled without LTO so that compiler just is not able to optimize it.

// mybuffer.c
#include <stdalign.h>
alignas(int) unsigned char buffer[sizeof(int)];
void *getbuffer() { return buffer; }


// main.c
#include <string.h>
#include <stdio.h>
#include "mybuffer.h"
int main() {
  void *data = getbuffer();
  // int *p = new (au.data) int;           // OK, au.data provides storage
  int *p = data;
  // char *c = new (au.data) char();       // OK, ends lifetime of *p
  char *c = data;
  *c = 0;
  // char *d = new (au.data + 1) char();
  char *d = (char*)data + 1;
  *d = 0;

  return *c + *d;
}
over 4 years ago · Santiago Trujillo Denunciar

0

The way the definition of Effective Type in 6.5p6 is written, it's unclear what it's supposed to mean in all corner cases--likely because there was never a consensus among Committee Members as to how all corner cases should be handled. Defect reports often add more confusion than clarity, since they use terms like the "active member" of a union when neither the Standard nor the defect reports specify what actions would set or change it.

If one wants to use an object of static or automatic duration as though it were a buffer without a declared type, a safe way of doing that should be to do something like the following:

void volatile *volatile dummy_vp;

void test(void)
{
  union {
    char dat[1000];
    unsigned long force_alignment;
  } buffer;
  void *volatile launder = buffer.dat;
  dummy_vp = &launder;
  void *storage_blob = launder;
  ...
}

Unless an implementation goes out of its way to test whether the read of launder happened to yield an address matching buffer.dat, it would have no way of knowing whether the object at that address had a declared type. Nothing in the Standard would forbid an implementation from behaving nonsensically if the address happened to match that of buffer.dat, but situations where performance improvements would justify the cost of the check aren't likely to be common enough for compilers to attempt such "optimization".

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda