如何将/剪切 uint256_t 转换为 uint8_t[]?

3

我有一个库使用 uint256_t 表示哈希值,另一个库使用 uint8_t 数组表示。

我猜应该有一种方法可以将 uint256_t 剪切/转换成 uint8_t[32]

但是,我还没有找到简单的转换方法。


2
假设大小端不是问题,reinterpret_cast<uint8_t*>(&value) 应该就足够了。 - HolyBlackCat
2
@HolyBlackCat 这是未定义行为。我建议使用std::memcpy代替。 - Resurrection
1
@Resurrection 如果 uint8_t 是一个 char 类型定义,那么它就不是 UB。可以通过 static_assert 来验证这一点。然而,确实 std::bit_cast<>() 或者在 C++20 之前的 std::memcpy() 版本通常是明确定义且更可取的 - 并且应该被优化为相同的代码。 - underscore_d
1
@Evg 坦白说,它不是 unsigned char typedef 的可能性几乎为零。如果失败了,你就去修复代码。 - HolyBlackCat
@Evg 那就换个方式做呗?我只是提到在进行 reinterpret_cast 操作之前如何确保其有效性。但我更希望不要用这种方式来实现,正如我之前已经说过的那样。 - underscore_d
显示剩余6条评论
3个回答

2

使用memcpy

你有两种不相关的类型,但你知道哈希的二进制表示对于两者都是相同的。在两种类型之间进行转换的最安全方式是通过memcpy

uint256_t source_hash;
// compute source_hash
// [...]

uint8_t dest_hash[32];
std::memcpy(dest_hash, &source_hash, 32);

请注意,这仅在二进制表示确实相同的情况下才有效。例如,如果库A以大端方式存储哈希值,而库B以小端方式存储,则需要进行更复杂的转换。虽然在哈希的情况下,二进制表示很可能是相同的,但在编写基于memcpy的转换之前,请务必仔细检查。
C ++20添加了std::bit_cast,也可以用于此类转换,并且很可能会生成与基于调用memcpy的解决方案完全相同的机器代码。如果您的编译器已经支持此功能,则可以选择bit_cast,因为它在语法上类似于内置的C ++转换。

2
从C++20开始,可以使用std::bit_cast<>()更好地表达相同的逻辑。 - underscore_d
@underscore_d 关于 bit_cast 的观点很好。我会把它加入到答案中。谢谢! - ComicSansMS
我该如何使用memcpy进行此转换?你能给我一个例子吗? - raycons
@underscore_d std::bit_cast 不能用于将数据转换为数组,因为数组不能作为函数的返回类型。 - eerorika
@eerorika 好的,那么 OP 可以使用 std::array,这个容器还有很多其他好处。 - underscore_d
显示剩余4条评论

1
在C++20中,我们将拥有std::bit_cast(https://en.cppreference.com/w/cpp/numeric/bit_cast)。在此之前,标准和定义的方法是使用std::memcpy
uint256_t msg = 1040449494439944;
uint8_t hash[32] = {};
std::memcpy(hash, &msg, sizeof(msg));

深入解释为什么在这种情况下调用reinterpret_cast的是不好的,由Jason Turner提供。


1
我刚刚尝试了以下内容,似乎运行良好。但是,我不确定可能产生的影响。
uint256_t msg = 1040449494439944;
uint8_t* hash =  (uint8_t*) &msg;
cout << sizeof(hash) << endl;

4
只有将其他对象重新解释为[无符号]字符才是合法的,而uint8_t不能保证是char类型,尽管在实践中通常是这种情况。 - underscore_d
3
在C++代码中,请避免使用旧的C风格转换,而是根据上下文使用正确的转换方式,例如(如果必要且您知道它是有效的)使用reinterpret_cast<uint8_t*> - underscore_d

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接