不了解编译器的行为
Not understanding the behavior of compiler
我想了解为什么下面的代码实际上有效,而没有给出seg错误。我让我的一位同事给我看了这个,我很惊讶。
有人能向我解释并指出一些好的链接来弥合我对此的理解吗?
struct Test {
int __in;
int __in1;
};
int main()
{
struct Test* t = NULL;
int i = &(t->__in1) + 4;
std::cout << i << std::endl;
}
arun@arun-desktop:~/Code$ g++ -fpermissive -g test8.cc
test8.cc: In function ‘int main()’:
test8.cc:11:24: warning: invalid conversion from ‘int*’ to ‘int’ [-fpermissive]
arun@arun-desktop:~/Code$ ./a.out
20
arun@arun-desktop:~/Code$
只有当您试图访问无效内存时,才会出现分段错误。您的代码只执行指针运算,调整指向Test
的指针以获得指向其成员之一的指针,而不读取或写入指针的目标。
这仍然是未定义的行为。孩子们,不要在家里这样做。
(此外,不要使用像__in1
这样的保留名称。也不要使用-fpermissive
来允许这样的无意义转换:类型系统会帮助你。)
struct Test {
int __in;
int __in1;
};
unsigned int fun ( void )
{
struct Test* t=NULL;
unsigned int i = (unsigned int)(&(t->__in1)) + 4;
return(i);
}
unsigned int fun2 ( void )
{
struct Test t;
unsigned int i = (unsigned int)(&(t.__in1)) + 4;
return(i);
}
我对您的代码做了一些修改,部分原因是为了帮助解决警告/错误。在第一种情况下,指针后面没有内存,因此它没有元素。您已将其指向NULL。您需要将它指向除null之外的其他值(因此数学值为null或零加上偏移量4加4),但这并不能解决问题。
在第二种情况下,它后面有一些内存,堆栈上有编译器分配的实际结构。所以我得到了这个:
00000000 <fun>:
0: e3a00008 mov r0, #8
4: e12fff1e bx lr
00000008 <fun2>:
8: e24dd008 sub sp, sp, #8
c: e28d0008 add r0, sp, #8
10: e28dd008 add sp, sp, #8
14: e12fff1e bx lr
因此,像这样的代码给你一个可以使用的地址是有希望的。
当您使用适当的类型转换和命令行选项构建程序以克服错误时,它也会输出8。
我不认为这样做地址数学有什么错,不是针对这个结构,但我可以看到这样一件事的一些用例。你应该能够获得结构中一个项的地址,并且你应该能够用这个地址进行地址计算,这种计算并不违法。
举个例子(只是在谷歌上搜索了一下,发现了另一个stackoverflow问题):
//g++ -std=c++11 ptr.c -o ptr
#include <iostream>
#include <cstdint>
struct Test {
int __in;
int __in1;
};
int main()
{
struct Test t;
intptr_t i = (intptr_t)(&(t.__in1))-(intptr_t)(&t) + 4;
std::cout << i << std::endl;
}
结果在我的机器上显示为8。。。要明白,没有理由在你的机器上它应该是一样的,你永远不应该依赖编译器如何构造结构及其大小。
相关文章:
- decltype(1, t) 应该是 l 值引用吗?(编译器不同意)
- 安装MinGW后C++编译器不起作用?
- 编译器不会使用 -std=c++11 编译智能指针
- 为什么编译器不检查被覆盖函数的存储类?
- Clang编译器不支持aarch64-apple-darwin上的-fxray-instrument
- 不了解链表实现,请帮忙.C++
- 我收到分段错误,但不了解分段错误发生的位置
- 为什么C++编译器不能做更好的常量折叠?
- 如何在构造函数中传递 const 引用时强制编译器不接受右值
- 如果函数包含静态变量,为什么编译器不执行内联?
- 关于内存泄漏,我有什么不了解的
- 为什么 C 编译器不在 for 循环体中给出重新声明错误?
- 为什么编译器不在同一翻译单元中警告 ODR 违规
- 如果类在 C++ 中具有常量或引用类型的非静态数据成员,为什么编译器不提供默认赋值运算符?
- 如果条件取决于模板类型并且在编译时已知,是否可以保证C++编译器不会生成分支?
- C++语法错误,编译器不会警告或 int v = func(&v) 出错;
- 编译器不了解递归功能以打印树级别的C
- 在C++中,为什么编译器不了解基类对象在编译时指向哪个对象?
- 不了解编译器的行为
- 不了解编译器如何搜索include