- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我遇到了一个有趣的场景,根据正确的操作数类型,我得到了不同的结果,但我无法真正理解其中的原因。
这是最少的代码:
#include <iostream>
#include <cstdint>
int main()
{
uint16_t check = 0x8123U;
uint64_t new_check = (check & 0xFFFF) << 16;
std::cout << std::hex << new_check << std::endl;
new_check = (check & 0xFFFFU) << 16;
std::cout << std::hex << new_check << std::endl;
return 0;
}
我在 Linux 64 位上使用 g++(gcc 版本 4.5.2)编译了这段代码:g++ -std=c++0x -Wall example.cpp -o example
输出是:
ffffffff81230000
81230000
第一种情况下输出的原因我不太明白。
为什么在某些时候将任何时间计算结果提升为 signed 64bit 值 (int64_t
) 从而导致符号扩展?
如果 16 位值首先向左移动 16 位然后提升为 64 位值,则在这两种情况下我都会接受结果为“0”。如果编译器首先将 check
提升为 uint64_t
然后执行其他操作,我也会接受第二个输出。
但是为什么 &
与 0xFFFF (int32_t
) 与 0xFFFFU (uint32_t
) 会导致这两个不同的输出?
最佳答案
这确实是一个有趣的极端案例。它只发生在这里,因为当您将 32 位用于 ìnt
uint16_t
用于无符号类型
这是 C++14 草案 n4296 中第 5 条表达式的摘录(强调我的):
10 Many binary operators that expect operands of arithmetic or enumeration type cause conversions ... This pattern is called the usual arithmetic conversions, which are defined as follows:
...
(10.5.3) — Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type shall be converted to the type of the operand with unsigned integer type.
(10.5.4) — Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, the operand with unsigned integer type shall be converted to the type of the operand with signed integer type.
你在 10.5.4 的情况下:
uint16_t
只有 16 位,而 int
是 32int
可以表示uint16_t
所以 uint16_t check = 0x8123U
操作数被转换为有符号 0x8123
并且按位 &
的结果仍然是 0x8123。
但是移位(按位,所以它发生在表示级别)导致结果是中间无符号 0x81230000 转换为 int 给出负值(技术上它是实现定义的,但这种转换是一种常见用法)
5.8 Shift operators [expr.shift]
...
Otherwise, if E1 has a signed type and non-negative value, and E1×2E2 is representable in the corresponding unsigned type of the result type, then that value, converted to the result type, is the resulting value;...
和
4.7 Integral conversions [conv.integral]
...
3 If the destination type is signed, the value is unchanged if it can be represented in the destination type; otherwise, the value is implementation-defined.
(注意这是 C++11 中真正的未定义行为...)
因此,您以将带符号的 int 0x81230000 转换为 uint64_t
结束,正如预期的那样给出 0xFFFFFFFF81230000,因为
4.7 Integral conversions [conv.integral]
...
2 If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type).
TL/DR:这里没有未定义的行为,导致结果的原因是将有符号的 32 位 int 转换为无符号的 64 位 int。 未定义行为的唯一部分是会导致符号溢出的转换,但所有常见的实现都共享这个,它是在 C++14 标准中定义的实现。
当然,如果你强制第二个操作数是无符号的,那么一切都是无符号的,你显然会得到正确的 0x81230000
结果。
[编辑] 正如 MSalters 所解释的,转变的结果只是 自 C++14 以来定义的实现,但在 C++11 中确实是未定义的行为 .移位运算符段落说:
...
Otherwise, if E1 has a signed type and non-negative value, and E1×2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
关于c++ - 带符号和无符号操作数的按位 '&',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38737024/
int enter_path(char** path) { char* standard = "./questions.txt"; printf("\n\t%s\n\t%s",
我有以下几行代码: #define PORT 9987 和 char *ptr = (char *)&PORT; 这似乎适用于我的服务器代码。但是当我在我的客户端代码中写它时,它给出了这个错误信息:
大家好,我在成员函数中有以下内容 int tt = 6; vector>& temp = m_egressCandidatesByDestAndOtMode[tt]; set& egressCandi
我知道您可以通过以下方式在正则表达式中使用 NOT 操作数: [^AB] :匹配除 "A" 之外的任何内容或"B" A(?!B) :匹配"A" ,后面不跟 "B" (?
我的代码如下,下面还解释了为什么会发生左值; typedef struct test_item { char id[MENU_NAME_LEN + NULL_SPACE]; MenuF
我正在审查一些 javascript 代码,程序员在几个地方使用了 >>。我试图在谷歌上搜索但找不到这个操作数/运算符的作用。所以我来了。下面的代码示例: var triplet=(((binarra
我使用以下行(希望这是最佳实践,如果不正确请纠正我)来处理命令行选项: #!/usr/bin/bash read -r -d '' HELP &2 for i in "${invalid_opti
我正在尝试编辑一个计时器应用程序,出现了这行代码。我该如何解决? let styleMask: Int = NSClosableWindowMask | NSTitledWindowMask 错误是:
我可以得到两个特定日期之间的差异,这将等于日期总数。现在我想将工作日除以总天数并得到整数输出。 @IBAction func go(_ sender: UIButton) { let con
我的项目有一个问题,它应该使用一个线程将每一行相加,然后将它们全部相加,但是我收到一个错误,指出左值需要作为一元 '&"操作数 pthread_create(&tid, NULL, &sum_line
我的代码有问题。有以下功能: static Poly PolyFromCoeff(int coeff); static Mono MonoFromPoly(const Poly *p, int exp
在 C# 中是否没有字符串的 OR 操作数? 我正在查看 Microsoft C# 操作数页面 - 没有关于字符串的任何类型的 OR。 我有一个要写的 if 语句: if (Convert.ToStr
下面的函数左移一个double操作数: double shl(double x,unsigned long long n) { unsigned long long* p = (unsigne
我在 Linux 中使用了以下简单的 ksh 脚本 #!/bin/ksh set -x ### Process list of *.dat files if [ -f *.dat ] then pri
我有一个使用 Entity Framework 的查询。它有许多不同的操作数,我对其优先级感到困惑。我得到了错误的结果。我需要所有 IsPaid == true 或 IsPaid == null 的记
我有以下代码来尝试创建一个约束数组以添加到 View 中: let views = ["button": button] let metrics = ["margin": 16] var constr
这个问题在这里已经有了答案: How to compare one value against multiple values - Swift (8 个答案) 关闭 6 年前。 我有一种情况,我必须
我使用 jquery $.ajax 将请求发送到服务器,它返回 JSON。 $.ajax({ url: 'moreMonth.ajax', data: { startIndex: id },
我的问题是程序没有按照“他”的预期读取代码。 我有 if (hero.getPos() == (6 | 11 | 16)) { move = new Object[] {"Up", "Righ
我在对象中创建线程时遇到问题。错误是需要作为一元“&”操作数的左值 CPP文件 #include "AirQ.h" static int i=0; AirQ::AirQ(int pinNo, bool
我是一名优秀的程序员,十分优秀!