/* [1] */
int i = -1;
unsigned u = (unsigned)i;
/* [2] */
int i = -1;
unsigned u;
memcpy(&u, &i, sizeof i);
/* [3] */
int i = -1;
unsigned u = *(unsigned *)&i;
Run Code Online (Sandbox Code Playgroud)
为了将带符号的整数进行位复制到其未签名的伙伴,[1]应该可以在大多数机器上工作,但据我所知,这是不保证的行为.
[2] 应该做我想要的,但我想避免调用库函数的开销.
那怎么样[3]?它能有效地达到我想要的目的吗?
Dra*_*rax 10
/* [4] */
union unsigned_integer
{
int i;
unsigned u;
};
unsigned_integer ui;
ui.i = -1;
// You now have access to ui.u
Run Code Online (Sandbox Code Playgroud)
警告:正如评论中所讨论的,这似乎没有问题C和未定义的行为C++,因为你的问题有两个标签我会留在这里.有关更多信息,请查看此SO问题:
那么我会建议对reinterpret_cast中C++:
/* [5] */
int i = -1;
unsigned u = reinterpret_cast<unsigned&>(i);
Run Code Online (Sandbox Code Playgroud)
/* [1] */
int i = -1;
unsigned u = (unsigned)i;
Run Code Online (Sandbox Code Playgroud)
↑这保证不适用于符号和1的补码机器,因为保证转换为无符号可以产生模2 n的有符号值,其中n是无符号类型中值表示位的数量.即转换是保证产生相同的结果,就好像有符号的类型使用二进制补码表示.
/* [2] */
int i = -1;
unsigned u;
memcpy(&u, &i, sizeof i);
Run Code Online (Sandbox Code Playgroud)
↑这样可以很好地工作,因为类型保证具有相同的大小.
/* [3] */
int i = -1;
unsigned u = *(unsigned *)&i;
Run Code Online (Sandbox Code Playgroud)
↑这是C++ 11及更早版本中的正式未定义行为,但它是标准中"严格别名"子句中包含的案例之一,因此每个现存的编译器都可能支持它.此外,它是一个什么样的例子reinterpret_cast是那里的.在C++ 14及更高版本中,关于未定义行为的语言已从(1)关于左值到右值转换的部分中删除.
如果我这样做,我会使用命名的C++强制转换为清晰.
然而,我会尝试一下有时看起来标准允许我做什么不切实际的事情编译器必须说的,特别是g ++具有严格的别名选项,无论它是什么,但也铿锵因为它被设计为g ++的直接替代品.
至少如果我计划使用那些编译器和选项的代码.
1) [conv.lval],C++ 11和C++ 14中的§4.1/ 1.
这是来自N3797文件的第4.7段"整体转换",这是C++ 14标准的最新工作草案:
如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模2 n,其中n是用于表示无符号类型的位数).[注意:在二进制补码表示中,此转换是概念性的,并且位模式没有变化(如果没有截断). - 尾注]
首先,世界上所有计算机都使用二进制补码表示.所以[1]是要走的路(除非你将C++移植到IBM 7090).
[3]在C和C++中都是正确的(从C++ 14开始,但之前没有); memcpy在这种情况下没有必要使用.(也就是说,没有理由不使用memcpy,因为它有效地传达了您的意图,显然是安全的,并且没有开销.)
C,6.5表达式:
7 - 对象的存储值只能由具有以下类型之一的左值表达式访问:[...]
- 对应于对象的有效类型的有符号或无符号类型,[...]
C++,[basic.lval]:
10 - 如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:[...]
- 与对象的动态类型对应的有符号或无符号类型,[...]
如您所见,两个标准中的措辞非常相似,因此可以依赖两种语言.
| 归档时间: |
|
| 查看次数: |
1972 次 |
| 最近记录: |