C++ 中的 Xor 加密,带有警告 "Use of a signed integer operand with a binary bitwise operator"
Xor encryption in C++ with warning "Use of a signed integer operand with a binary bitwise operator"
我正在学习 c++ 中的简单 XOR 加密算法。
下一个代码可以正常工作:
void test(int8_t* data, const int data_length) {
const uint8_t key = 123;
for (int index = 0; index < data_length; index++)
data[index] = data[index] ^ key;
}
我得到的data是有符号的,因此类型是int8_t.
问题是编译器显示下一个警告:
"Use of a signed integer operand with a binary bitwise operator”
我可以通过在执行 XOR 操作时将 data 与 uint8_t 强制转换来使警告消失,但我没有'知道其中的含义。我做了一些测试,似乎没有问题,但我很困惑,因为数据可以包含有符号值,所以我不确定通过转换它是否会弄乱数据。
即使数据可以包含负值,转换为 uint8_t 是否正确?还是我应该忽略警告?
编译器发出警告是因为不应对有符号整数执行按位运算。在 C++20 之前的 C++ 中,允许有符号整数的不同表示,这意味着相同的数字可以在不同的机器和编译器上由不同的位模式表示。这使得对有符号整数进行位操作的结果不可移植。当然,intN_t
总是需要使用 two's complement 表示(并且 C++20 将该要求扩展到所有有符号整数),仍然不建议使用有符号整数进行按位运算。
在您的特定情况下,data[index]
和 key
都被提升为 int
以执行异或运算。然而,由于 data[index]
是一个带符号的整数,它的值得到符号扩展,而无符号的 key
得到零扩展。这意味着 XOR 仅影响中间 int
值的低 8 位,结果可能不在 int8_t
范围内。当您将结果分配回 data[index]
时,可能会发生有符号溢出,这在 C++ 中是 UB(在 C++20 之前;从 C++20 开始,它被明确定义为截断高位)。
在这种情况下正确的做法是将您的数据视为原始字节数组,而不管这些字节代表什么值。这意味着,您应该使用 std::byte
或 std::uint8_t
来表示输入和输出数据。这样您将对无符号整数进行操作,并且没有可移植性或潜在的溢出问题。
对于c++20,你应该使用按位复制:
void test(int8_t* data, const int data_length) {
const uint8_t key = 123;
for (int index = 0; index < data_length; index++){
auto const encrypted = std::bit_cast<std::byte>(data[index]) ^ key;
data[index] = std::bit_cast<int8_t>(encrypted);
}
}
对于以前的版本,您应该static_cast将有符号类型转换为相应的无符号类型。
void test(int8_t* data, const int data_length) {
const uint8_t key = 123;
for (int index = 0; index < data_length; index++){
auto const encrypted = static_cast<std::byte>(data[index]) ^ key;
data[index] = static_cast<int8_t>(encrypted);
}
}
我正在学习 c++ 中的简单 XOR 加密算法。
下一个代码可以正常工作:
void test(int8_t* data, const int data_length) {
const uint8_t key = 123;
for (int index = 0; index < data_length; index++)
data[index] = data[index] ^ key;
}
我得到的data是有符号的,因此类型是int8_t.
问题是编译器显示下一个警告:
"Use of a signed integer operand with a binary bitwise operator”
我可以通过在执行 XOR 操作时将 data 与 uint8_t 强制转换来使警告消失,但我没有'知道其中的含义。我做了一些测试,似乎没有问题,但我很困惑,因为数据可以包含有符号值,所以我不确定通过转换它是否会弄乱数据。
即使数据可以包含负值,转换为 uint8_t 是否正确?还是我应该忽略警告?
编译器发出警告是因为不应对有符号整数执行按位运算。在 C++20 之前的 C++ 中,允许有符号整数的不同表示,这意味着相同的数字可以在不同的机器和编译器上由不同的位模式表示。这使得对有符号整数进行位操作的结果不可移植。当然,intN_t
总是需要使用 two's complement 表示(并且 C++20 将该要求扩展到所有有符号整数),仍然不建议使用有符号整数进行按位运算。
在您的特定情况下,data[index]
和 key
都被提升为 int
以执行异或运算。然而,由于 data[index]
是一个带符号的整数,它的值得到符号扩展,而无符号的 key
得到零扩展。这意味着 XOR 仅影响中间 int
值的低 8 位,结果可能不在 int8_t
范围内。当您将结果分配回 data[index]
时,可能会发生有符号溢出,这在 C++ 中是 UB(在 C++20 之前;从 C++20 开始,它被明确定义为截断高位)。
在这种情况下正确的做法是将您的数据视为原始字节数组,而不管这些字节代表什么值。这意味着,您应该使用 std::byte
或 std::uint8_t
来表示输入和输出数据。这样您将对无符号整数进行操作,并且没有可移植性或潜在的溢出问题。
对于c++20,你应该使用按位复制:
void test(int8_t* data, const int data_length) {
const uint8_t key = 123;
for (int index = 0; index < data_length; index++){
auto const encrypted = std::bit_cast<std::byte>(data[index]) ^ key;
data[index] = std::bit_cast<int8_t>(encrypted);
}
}
对于以前的版本,您应该static_cast将有符号类型转换为相应的无符号类型。
void test(int8_t* data, const int data_length) {
const uint8_t key = 123;
for (int index = 0; index < data_length; index++){
auto const encrypted = static_cast<std::byte>(data[index]) ^ key;
data[index] = static_cast<int8_t>(encrypted);
}
}