将要存储在 int 中的左移 short 是否未定义?
Is left shifted short that is going to be stored in an int is UNDEFINED?
我正在阅读一本实现自己动手的 DNS 消息的书 reader,它会尝试查看某个特定字段是否设置为真。
书中使用的一段代码我看不太懂
const int qdcount = (msg[10] << 8) + msg[11];
msg
是 ==> char
类型(即 8 位)
qdcount
==> 应该是一个 16 位的字段,包含 DNS 查询的数量(由 2 个字段组成 msg[10]
和 msg[11]
)
那么这段代码是如何工作的(例如,如果 msg[10] = 01001 0001)将其左移 8 应该会产生 (1000 0000),即 UB,那么完成的任何计算都会导致错误的答案。假设msg[11] = 0010 1111
。计算结果是 1000 0000 + 0010 1111 对吧?。那么这行代码是如何工作的。
来自 C11 – ISO/IEC 9899:2011 draft paragraph 6.5.7.4 version linked here.
[...] E1 << E2 [...]
If E1 has a signed type and nonnegative value, and E1 × 2^E2 is
representable in the result type, then that is the resulting
value; otherwise, the behavior is undefined.
是的。左移带符号的值可能会导致未定义的行为。
您代码中的另一件事实际上导致您感到困惑:
The integer promotions are performed on each of the operands.
这意味着在移位之前,您的操作数会扩展到 int
。因此,通过将位移入符号位(假设 sizeof(int)>16
),移位 8 不会导致溢出。
至少有 2 个独立的考虑因素。
char
是有符号 或无符号?
int
16 位或更宽?
(msg[10] << 8) + msg[11];
大部分问题取决于:
The result of E1 << E2 is E1 left-shifted E2 bit positions ...
If E1 has a signed type and nonnegative value, and E1 *2E2 is
representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
char
已签名,int
任意大小
msg[10]
被提升为 int
并左移 8。当值 msg[10]
为正时这很好,而当负值为负时未定义的行为,因为左移负值是 UB。
char
是 unsigned,int
比 16 位宽
msg[10]
提升为 int
并向左移动 8。这很好,所有 msg[10]
值都没有问题。
char
是无符号,int
是16位
msg[10]
提升为 int
并左移 8。当 msg[10] < 128
时这很好,否则是 UB 移入符号位置 - 正值不可表示。
移位时最好使用无符号类型。
// char msg[100];
// const int qdcount = (msg[10] << 8) + msg[11];
char unsigned msg[100];
const unsigned qdcount = ((unsigned) msg[10] << 8) + msg[11];
我正在阅读一本实现自己动手的 DNS 消息的书 reader,它会尝试查看某个特定字段是否设置为真。 书中使用的一段代码我看不太懂
const int qdcount = (msg[10] << 8) + msg[11];
msg
是 ==> char
类型(即 8 位)
qdcount
==> 应该是一个 16 位的字段,包含 DNS 查询的数量(由 2 个字段组成 msg[10]
和 msg[11]
)
那么这段代码是如何工作的(例如,如果 msg[10] = 01001 0001)将其左移 8 应该会产生 (1000 0000),即 UB,那么完成的任何计算都会导致错误的答案。假设msg[11] = 0010 1111
。计算结果是 1000 0000 + 0010 1111 对吧?。那么这行代码是如何工作的。
来自 C11 – ISO/IEC 9899:2011 draft paragraph 6.5.7.4 version linked here.
[...] E1 << E2 [...]
If E1 has a signed type and nonnegative value, and E1 × 2^E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
是的。左移带符号的值可能会导致未定义的行为。
您代码中的另一件事实际上导致您感到困惑:
The integer promotions are performed on each of the operands.
这意味着在移位之前,您的操作数会扩展到 int
。因此,通过将位移入符号位(假设 sizeof(int)>16
),移位 8 不会导致溢出。
至少有 2 个独立的考虑因素。
char
是有符号 或无符号?int
16 位或更宽?(msg[10] << 8) + msg[11];
大部分问题取决于:
The result of E1 << E2 is E1 left-shifted E2 bit positions ...
If E1 has a signed type and nonnegative value, and E1 *2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
char
已签名,int
任意大小
msg[10]
被提升为 int
并左移 8。当值 msg[10]
为正时这很好,而当负值为负时未定义的行为,因为左移负值是 UB。
char
是 unsigned,int
比 16 位宽
msg[10]
提升为 int
并向左移动 8。这很好,所有 msg[10]
值都没有问题。
char
是无符号,int
是16位
msg[10]
提升为 int
并左移 8。当 msg[10] < 128
时这很好,否则是 UB 移入符号位置 - 正值不可表示。
移位时最好使用无符号类型。
// char msg[100];
// const int qdcount = (msg[10] << 8) + msg[11];
char unsigned msg[100];
const unsigned qdcount = ((unsigned) msg[10] << 8) + msg[11];