c - C中的胖指针
问题描述
我已经阅读了有关Cello 胖指针库的信息,并想知道在 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 数组并根据需要重新转换它)。
特别是在这个问题中,人们说以下内容实际上是不可移植的:
struct header {
size_t len;
unsigned char data[1];
};
因为访问第一个元素之外的数据是 UB。另一件事是这些线条((struct header*)ret)->length = strlen(cstr);
和struct header* tmp = sized_string - sizeof(struct header);
我看起来不对(因为指针转换),我没有看到更好的方法来编写它们。
解决方案
您的示例仅从固定偏移量放置和读取。所以至少指针算术是完全合法的。至少只要类型只是一个char
.
但是有问题的是对齐。这还没有违反语言标准,但实际数据的对齐方式比 x86 上的编译器默认提供的对齐方式更差。
因此,如果编译器默认对齐到 8 个字节(x86 上的 gcc 和 msvc)或 16 个字节(x64 上),则您的示例代码仅提供一半对齐。
这可能是非法的,如果编译器假设内存对齐(否则这将通过匹配malloc
实现以及堆栈布局和结构中的填充来确保)。根据架构,它甚至可能导致错误,因为指令可能需要最小对齐。
推荐阅读
- asp.net-core - ASP NET CORE GetConnectionString 不起作用
- java - 能够使用 Style 项在代码中设置颜色,因此不需要关心当前的应用程序主题
- python - 使用 jupyter notebook 运行选定的行并显示输出
- javascript - 仅在移动设备中添加活动课程
- java - Java 电子邮件:如何在保存和返回实体之前发送电子邮件?
- scroll - 使用 jumpTo 方法时,FLUTTER 滚动控制器抛出堆栈溢出错误
- vba - 使用 VBA 删除包含关键字的 Powerpoint 幻灯片
- python - 使用 glob 打开文件夹中的各种文件时出错
- swift - 如何在 Swift 中成功编译 NSClassFromString
- keras - 在具有多个多元时间序列的 keras 上训练 LSTM 模型