Jan*_*dec 6 c c++ language-lawyer
像这样的代码过去常常起作用,它应该是什么意思.是否允许编译器(通过规范)使其成为错误?
我知道它正在失去精确度,我会很高兴收到警告.但是它仍然有一个明确定义的语义(至少对于未定义的缩小版本定义)并且用户可能想要这样做.
我有遗留代码,我不想重构太多,因为它相当棘手并且已经调试过.它做了两件事:
有时在指针变量中存储整数.如果代码之前存储了整数,则代码仅将指针强制转换为整数.因此,当演员阵容缩小时,溢出在现实中永远不会发生.代码经过测试和运行.
当存储整数时,它总是适合普通的旧无符号,因此改变类型不被认为是一个好主意并且指针传递相当多,所以改变它的类型将有点侵入性.
使用地址作为哈希值.一个相当常见的事情.哈希表对于扩展类型没有任何意义.
代码使用plain unsigned作为哈希值,但请注意,更常见的类型size_t 仍可能生成错误,因为无法保证sizeof(size_t)> = sizeof(void *).在具有分段内存和远指针的平台上,size_t只需要覆盖偏移部分.
那么什么是最不易侵入的合适的解决方法?已知代码在使用不会产生此错误的编译器编译时工作,所以我真的想要进行操作,而不是更改它.
void *x;
int y;
union U { void *p; int i; } u;
Run Code Online (Sandbox Code Playgroud)
*(int*)&x并且u.p = x, u.i是不等同于(int)x并且不相反(void *)y.在大端架构上,前两个将返回较低地址上的字节,而后一个将处理低位字节,这些字节可能驻留在较高地址上.*(int*)&x并且u.p = x, u.i都是严格别名侵犯,(int)x是不是.C++,5.2.10:
4 - 指针可以显式转换为足以容纳它的任何整数类型.[...]
C,6.3.2.3:
6 - 任何指针类型都可以转换为整数类型.[...]如果结果无法以整数类型表示,则行为未定义.[...]
因此(int) p,如果int是32位且void *是64位则是非法的; 一个C++编译器是正确的给你一个错误,而C编译器可能会给出一个错误的翻译或发出一个具有未定义行为的程序.
你应该写,添加一个转换:
(int) (intptr_t) p
Run Code Online (Sandbox Code Playgroud)
或者,使用C++语法,
static_cast<int>(reinterpret_cast<intptr_t>(p))
Run Code Online (Sandbox Code Playgroud)
如果您要转换为无符号整数类型,请转换为via uintptr_t而不是intptr_t.
这是一个很难“一般”解决的问题,因为“失去精度”表明您的指针大于您尝试存储它的类型。在您看来,这很可能是“没问题”,但编译器担心您将把 int 值恢复回指针,该指针现在已经丢失了高 32 位(假设我们正在谈论 32 位 int 和 64 位指针 - 还有其他可能的组合)。
它uintptr_t与系统上的任何指针大小兼容,因此通常可以通过以下方式克服实际错误:
int x = static_cast<int>(reinterpret_cast<uintptr_t>(some_ptr));
Run Code Online (Sandbox Code Playgroud)
这将首先从指针强制一个大整数,然后将大整数转换为较小的类型。
| 归档时间: |
|
| 查看次数: |
5149 次 |
| 最近记录: |