为啥我可以将 static_cast void* 转换为 int* 而不能转换为 int*&?
Posted
技术标签:
【中文标题】为啥我可以将 static_cast void* 转换为 int* 而不能转换为 int*&?【英文标题】:Why can I static_cast void* to int* but not to int*&?为什么我可以将 static_cast void* 转换为 int* 而不能转换为 int*&? 【发布时间】:2018-02-18 18:36:35 【问题描述】:API 使用void*
来存储无类型指针偏移量。这有点hacky,但没关系。
为了表达我的偏移算法,我尝试做这样的事情
int main ()
void * foo;
foo = static_cast <int *> (nullptr) + 100;
static_cast <int * &> (foo) += 100;
最后一行编译失败(gcc)
x.cpp:7:28: error: invalid static_cast from type ‘void*’ to type ‘int*&’
修复很简单:
foo = static_cast <int *> (foo) + 100;
但是为什么不允许第一个呢?
在你回答“因为标准这么说”之前,为什么标准这么说?第一种方法有什么危险吗?还是只是疏忽?
【问题讨论】:
理论上,不能保证void*
和int*
的大小相同。作为左值,它们可能不兼容。虽然这在实践中是不可能的。
@liliscent:在实践中,int*
需要的位比void*
少,因此虽然可能很少见,但它们实际上是不同的大小并非不可能(相对于有几个未使用/填充位在int*
)
【参考方案1】:
不允许使用与不允许使用 int i; static_cast<long &>(l) = 3L;
相同的原因。
当然,在很多实现中(int
和 long
具有相同的大小、表示和对齐方式),它可以工作。但是对于所有实现来说,强制转换的有效规则几乎都是相同的,显然这在int
和long
具有不同大小的平台上永远不会起作用,这意味着不可能允许访问一个作为另一个那些平台。
从历史上看,void *
和 int *
有不同的表示形式。
后来,在标准声明像访问void *
一样访问int *
是无效的之后,实现也开始在有效程序不这样做的假设下进行优化:
void *f (void **ppv, int **ppi)
void *result = *ppv;
*ppi = nullptr;
return result;
允许实现将其优化为
void *f (void **ppv, int **ppi)
*ppi = nullptr;
return *ppv;
当它们减少代码大小或提高效率时,这些优化现在很常见。如果允许f
被称为void *pv = &pv; f (pv, &static_cast<int*&>(pv));
,则此优化将无效。由于此类优化已被证明是有用的,因此规则不太可能改变。
【讨论】:
最后一个例子确实很有说服力,以前我认为这些差异只是理论上的。经过 clang 测试,这种优化甚至针对-O1
。
很好的答案,谢谢。但是为什么我的x=static_cast<int*>(x)+n
修复也不被禁止?
@spraff 这就像int i = 3; i = static_cast<long>(i) + 1L;
。那里没有对位的重新解释,只有值的转换。即使void *
和int *
有不同的表示,那么static_cast<int*>(x)
将改变表示,n
将被添加,隐式转换回void *
将改变表示。以上是关于为啥我可以将 static_cast void* 转换为 int* 而不能转换为 int*&?的主要内容,如果未能解决你的问题,请参考以下文章
使 .natvis 将 SmartPointer<T> 显示为 static_cast<T*>(void*)
错误 C2440:“static_cast”:无法从“void (__thiscall Visualizza::*)(char [])”转换为“AFX_PMSG”