Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

393
Views
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 answers
Answer question

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 Report

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!