我很好奇C++中类型惩罚指针/数组的约定.这是我目前的用例:
通过将其视为32位整数数组(我们知道它的总长度是4的倍数),然后将所有值相加并忽略溢出,计算二进制blob数据的简单32位校验和.
我希望这样的函数看起来像这样:
uint32_t compute_checksum(const char *data, size_t size) { const uint32_t *udata = /* ??? */; uint32_t checksum = 0; for (size_t i = 0; i != size / 4; ++i) checksum += udata[i]; return udata; }
现在我的问题是,您认为转换data
为"最佳"的方式是udata
什么?
C风格演员?
udata = (const uint32_t *)data
假设所有指针都是可转换的C++强制转换?
udata = reinterpret_cast(data)
C++在任意指针类型之间使用中间转换void*
?
udata = static_cast(static_cast (data))
通过工会铸造?
union { const uint32_t *udata; const char *cdata; }; cdata = data; // now use udata
我完全意识到这不是一个100%可移植的解决方案,但我只希望在一小部分平台上使用它,我知道它可以工作(即未对齐的内存访问和指针别名的编译器假设).你会推荐什么?
就C++标准而言,litb的答案是完全正确的,也是最便携的.无论是通过C风格的强制转换,还是强制转换const char *data
为a const uint3_t *
,都会违反严格的别名规则(请参阅了解严格别名).如果您使用完全优化进行编译,那么代码很可能不会正确.static_cast
reinterpret_cast
通过联合(例如litb my_reint
)进行转换可能是最好的解决方案,尽管它在技术上违反了规则,如果您通过一个成员写入联合并通过另一个成员读取它,则会导致未定义的行为.但是,几乎所有编译器都支持这一点,并且它会产生预期的结果.如果您绝对希望符合标准100%,请使用位移方法.否则,我建议通过联盟进行投射,这可能会给你更好的表现.
忽略效率,为了简化代码我会做:
#include#include #include uint32_t compute_checksum(const char *data, size_t size) { std::vector intdata(size/sizeof(uint32_t)); std::memcpy(&intdata[0], data, size); return std::accumulate(intdata.begin(), intdata.end(), 0); }
我也喜欢litb的最后一个答案,即依次移动每个char的那个,除了因为char可能会被签名,我认为它需要一个额外的掩码:
checksum += ((data[i] && 0xFF) << shift[i % 4]);
当打字类型是一个潜在的问题时,我宁愿不输入双关语而不是安全地尝试这样做.如果您不首先创建任何不同类型的别名指针,那么您不必担心编译器可能对别名做什么,维护程序员也不会通过联合看到您的多个static_cast.
如果你不想分配这么多额外的内存,那么:
uint32_t compute_checksum(const char *data, size_t size) { uint32_t total = 0; for (size_t i = 0; i < size; i += sizeof(uint32_t)) { uint32_t thisone; std::memcpy(&thisone, &data[i], sizeof(uint32_t)); total += thisone; } return total; }
足够的优化将完全取消内存中的memcpy和额外的uint32_t变量,只需读取一个未对齐的整数值,无论以何种最有效的方式在您的平台上执行,直接从源数组中取出.我希望其他"严肃"的编译器也是如此.但是这个代码现在比litb更大了,所以没有什么可说的,除了我之外更容易变成一个与uint64_t一样好用的函数模板,并且我的工作作为本地字节序而不是选择一点-endian.
这当然不是完全便携的.它假定sizeof(uint32_t)字符的存储表示以我们想要的方式对应于uin32_t的存储表示.问题暗示了这一点,因为它表明一个人可以被"视为"另一个人.Endian-ness,char是否是8位,以及uint32_t是否使用其存储表示中的所有位显然可以侵入,但问题暗示它们不会.