Пакет урезанных C-структур - PullRequest
0 голосов
/ 18 мая 2018

У меня есть библиотека C (я использую ее в C ++), которая определяет структуру и функцию для работы с ней.

struct s {
  type1 x1;
  type2 x2;
  type3 x3;
  type4 x4;
  type5 x5;
};

void f(s* x);

Я знаю, что f ничего не делает с участиемs::x4 или s::x5.Поскольку оба они бесполезны для моей цели, и у меня есть много экземпляров s, я хотел бы разместить их в массиве, который упаковывает их так, что s[n+1] начинается сразу после s[n].x3. Будет ли что-то похожее на следующий результат с неопределенным поведением? Предположим, что x4 и x5 никогда не используются.

struct s_trimmed {
  type1 x1;
  type2 x2;
  type3 x3;
};

size_t num_s = 1000;
char *mem = new char[stuff_before + num_s*sizeof(s_trimmed) + stuff_after];

for (size_t i=0; i<nums; ++i)
  f((s*)(mem + stuff_before + i*sizeof(s_trimmed)));

mem - это массив char, потому чтоэто просто кусок памяти, и я хочу, чтобы в нем были и другие вещи, кроме экземпляров s.

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Если вы избежите каких-либо проблем, связанных с выравниванием, ваш код попадет в категорию программ, которые авторы Стандарта могли ожидать, что реализации качества будут обрабатываться с пользой, но какой раздел N1570 6.5p7 Стандарта позволит реализациям обрабатыватьпроизвольным образом.Обратите внимание, что способ написания Стандарта C, даже что-то вроде:

struct foo {int x;} s = {0};
s.x = 1;

, попадает в эту же категорию, потому что Стандарт не описывает каких-либо обстоятельств, при которых lvalue типа int может использоваться длявлияет на объект типа struct foo, а определение lvalue не учитывает идею о том, что lvalue может иметь тип int, но иметь связь 6.5p7 с каким-либо другим типом.

Нет причинпочему любой компилятор качества должен испытывать трудности с распознаванием того кода, который преобразует T1* в T2* и передает его функции, которая действует на T2*, может получить доступ к объекту типа T1*,В отсутствие флага -fno-strict-aliasing gcc и clang сознательно закрывают глаза на такие возможности, но использование этого флага заставит их вести себя как качественные компиляторы.

0 голосов
/ 18 мая 2018

Пока ваша функция f не имеет дело с x4 и x5, вы можете безопасно скопировать структуру в массив без знака с усеченной длиной и передать ее функции. Пример программы может выглядеть примерно так:

#include <iostream>
#include <memory.h>
struct s {
  double x1;
  float x2;
  long long x3;
  int x4;
  int x5;
};
struct s_trimmed {
  double x1;
  float x2;
  long long x3;
};
void f(s* x)
{
  std::cout<<x->x1<<std::endl;
  std::cout<<x->x2<<std::endl;
  std::cout<<x->x3<<std::endl;
}
int main() {
  size_t nums = 2;
  unsigned char *mem = new unsigned char[nums*sizeof(s_trimmed)];
  unsigned int start = 0;
  for(int i=0;i<nums;i++)
  {
    s* s_obj = new s;
    s_obj->x1 = 10.5;
    s_obj->x2 = 89.98;
    s_obj->x3=28765;
    s_obj->x4=1;
    s_obj->x5=5;
    memcpy(mem+start,s_obj,sizeof(s_trimmed));
    start = start + sizeof(s_trimmed);
    delete s_obj;
    s_obj = nullptr;
  }
  start = 0;
  for(int i=0;i<nums;i++)
  {
    unsigned char *memf = new unsigned char[sizeof(s_trimmed)];
    memcpy(memf,mem+start,sizeof(s_trimmed));    
    f((s*)memf);    

  }
  delete[] mem;
  mem=nullptr;
  return 0;
}
...