包装修剪的C结构

时间:2018-05-18 04:28:09

标签: c++ c memory-management undefined-behavior

我有一个C库(我在C ++中使用它),它定义了一个结构和一个对它进行操作的函数。

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

void f(s* x);

我知道f没有执行涉及s::x4s::x5的任何事情。由于它们都没有用于我的目的,并且我有很多s的实例,我想将它们分配到一个包含它们的数组中,以便s[n+1]s[n].x3之后启动{ {1}}。 执行以下操作会导致未定义的行为吗?假设从未使用过x4x5

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 :(得分:1)

如果您避免任何与对齐相关的问题,您的代码将属于标准作者可能期望质量实现有效处理的程序类别,但标准的N1570 6.5p7部分将允许实现处理以任意方式。请注意C标准的编写方式,即使是:

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

属于同一类别,因为标准没有描述任何类别 可以使用类型int的左值来影响对象的情况 类型为struct foo,它的左值定义也不包含左值可能具有int类型但与其他类型有6.5p7关联的想法。

没有理由认为任何 quality 编译器在识别将T1*转换为T2*并将其传递给作用于T2*可能会访问T1*类型的对象。在没有-fno-strict-aliasing标志的情况下,gcc或clang故意对这种可能性视而不见,但使用该标志会使它们像质量编译器一样。

答案 1 :(得分:0)

只要您的函数f没有处理x4和x5,那么您可以安全地将结构复制到带有修剪长度的unsigned char数组并将其传递给function.Sample程序可以是这样的:

#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;
}