C中的胖指针

时间:2018-05-16 17:00:01

标签: c pointers language-lawyer undefined-behavior

我已经阅读了Cello fat pointer library,并想知道在C中实际上是否允许在某些数据前加上标题,例如像这样的东西:

struct header
{
  size_t length;
};

char* create_string(const char* cstr)
{
  void* ret = malloc(sizeof(struct header)+strlen(cstr)+1);
  ((struct header*)ret)->length = strlen(cstr);
  strcpy((char*)ret + sizeof(struct header), cstr);
  return (char*)ret + sizeof(struct header);
}

size_t get_length(const char* sized_string)
{
  struct header* tmp = sized_string - sizeof(struct header);
  return tmp->length;
}

这个例子是一个字符串,但它可能是存储的任何其他内容,甚至可能是一个不是数组的东西,在这种情况下,标题可能有不同类型的元数据。

我知道sds使用灵活的数组成员,但这需要c99并且不像这种方法那么灵活(除非你只使用了一个通用的char数组并根据需要重新设置它)。

具体而言in this question人说以下内容实际上并不可移植:

struct header {
  size_t len;
  unsigned char data[1];
};

因为访问第一个元素之外的数据是UB。另一件事是((struct header*)ret)->length = strlen(cstr);struct header* tmp = sized_string - sizeof(struct header);行看起来不对(因为指针强制转换),我没有看到更好的方法来编写它们。

1 个答案:

答案 0 :(得分:6)

您的示例仅放置和读取固定偏移量。所以至少指针算术是完全合法的。至少只要类型只是malloc

但问题是对齐。这还没有违反语言标准,但是实际数据的对齐比例如x86上的编译器默认提供。

因此,如果编译器默认情况下对齐为8个字节(x86上的gcc和msvc)或16个字节(x64上),则示例代码仅提供对齐的一半。

如果编译器假设对齐的内存(否则可以通过匹配Function GetName(Source As String) Dim arr() As String 'declares a dynamic array arr = VBA.Split(Source, " ") 'an array of words split by space from the Source string is built 'Ubound function gets the last position of items in the array Name = "" For i = LBound(arr) To UBound(arr) Name = Name + " " + arr(i) Next i End Function 实现来确保,以及堆栈布局和结构中的填充),这可能是非法的。根据架构,它甚至可能导致错误,因为指令可能需要最小的对齐。