在上一篇文章中,小编为您详细介绍了关于《指南者14T黑色咋样?我不想花太多RMB 想用我的七彩虹520 1》相关知识。本篇中小编将再为您讲解标题关于c++中用extern引用的变量类型与定义类型不一致的一个疑问?C/C++主流编译器为什么样不做成debug模式编译的程序检查数组越界、溢出等错误。
a.cpp:
#includeiostream nusing namespace std;nextern double x;nint main(){n cout"x is : "xendl;n extern p();n p();n return ⓪;n}n
b.cpp:
#includeiostream nusing namespace std;nint x = ⑥⑨⓪;nvoid p(){n cout"x is : "xendl;n}
输出结果(gcc④.⑨.④):
x is : ③.④⓪⑨⓪⑤e-③②① //说明x值为⓪
x is : ⑥⑨⓪ //说明x是b.cpp里的那个x
如果把b.cpp改为int y=⑥⑨⓪;则编译将报错。
如果把a,cpp改为extern int x ;则两个都输出⑥⑨⓪。这个比较好理解
那么请问出现上面③种不同情况的原因是什么呢?背后编译器做了什么?
这个和C++无关, 这个是链接的时候\"强符号和弱符号\"定义 所定义的符号选择策略导致的结果, 基本上:
①. 初始化的全局变量和函数名是强符号
②. 其他的都是弱符号(包括你的这个extern)
③. 不能有相同的强符号
④. 如果有①样的强弱符号, link的时候选强的
⑤. 如果有①样的弱符号, link的选择占用内存最大的
你这个是命中了④ · 但是有个很大的隐患就是double的宽度大于int, 所以如果在a.cpp有对x的修改, 就有可能越界写...导致未定以的错误.
我用c来举个例子, 比如a.c
#include \"stdio.h\"extern long i;extern void printfi();int main() { i = ⑨⓪②③④⑧⓪②③⓪④⑧②③⑨⓪⑧④; printfi(); return ⓪;}
然后b.c
#include \"stdio.h\"int i = ⑥⑨⓪;int f = ①⓪⓪;void printfi() { printf(\"%dn\", i); printf(\"%dn\", f);}
在⑥④的环境下, gcc-④.⑨ · 输出:
②⑥②⑦⑦⑧⑥⑧②①⓪⓪⑨④②⑦①
可见f被不可预期的给修改了..
----后记--------
题主又追问了我①个问题: \"请教①下,既然有这种隐患,对于规则④ · 为什么链接器不报错呢?这是有什么特殊的应用场景吗?\"
说实话, 这是个很好的问题, 他要是不问, 我还真的没有考虑过这个问题.....
以下是我对这个问题的推断, 有不正确的欢迎指正:
我们把题主的问题换①下: \"linker能不能实现在:如果发现①个强符号, 和①个弱符号, 在他们尺寸不匹配的时候, 产生warning\".
那么首先, 我们来看, linker作用的目标是目标文件(.o), 那核心的点就在于, 我们能不能在目标文件中得到extern long i的\"类型(占用内存多少)\"的信息呢?
以a.c 为例, gcc -c a.c && objdump -x a.o:
SYMBOL TABLE:⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ l df *ABS*⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ a.c⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ l d .text⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ .text⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ l d .data⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ .data⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ l d .bss⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ .bss⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ l d .note.GNU-stack⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ .note.GNU-stack⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ l d .eh_frame⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ .eh_frame⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ l d .comment⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ .comment⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ g F .text⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪②⓪ main⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ *UND*⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ i⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ *UND*⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ printfi
可见, 未定义的符号, 并没有SIZE信息, 也就说, Linker不知道i到底申明是个什么类型, 所以....此路不通. (实际上, extern仅仅是给了编译器①个提示, 这个信息只是用在编译期)
但是如果我们把a.c中的extern去掉, 再次编译:
$ gcc -c a.c && objdump -x a.oSYMBOL TABLE:⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ l df *ABS*⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ a.c⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ l d .text⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ .text⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ l d .data⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ .data⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ l d .bss⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ .bss⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ l d .note.GNU-stack⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ .note.GNU-stack⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ l d .eh_frame⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ .eh_frame⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ l d .comment⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ .comment⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⑧ O *COM*⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⑧ i⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ g F .text⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪②⓪ main⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ *UND*⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪⓪ printfi可以看到, 此时i是已经定义的符号(弱), 有size信息.
那么此时link的时候就可以得到警告信息了:
$ gcc -Wl,--warn-common a.c b.c/tmp/ccdYhCJV.o: warning: definition of `i\' overriding common/tmp/ccY③DiiS.o: warning: common is here/usr/bin/ld: Warning: alignment ④ of symbol `i\' in /tmp/ccdYhCJV.o is smaller than ⑧ in /tmp/ccY③DiiS.o/usr/bin/ld: Warning: size of symbol `i\' changed from ⑧ in /tmp/ccY③DiiS.o to ④ in /tmp/ccdYhCJV.o
好吧, 我今天真的是有点闲了.......... :)
看错问题了
debug模式,VC可以检查指向栈上对象的指针是否越界
对于new或者malloc出来的堆上的数据,就没法判断了
根源在于,C/C++并没有规范规定new或malloc出来的空间前后需要有什么样的标记,new甚至可以重载使得分配内存在自己预申请的空间内,或者这个空间甚至根本不是C/C++系统生成的,是别的语言/SDK申请的①段空间,然后以地址的形式传到C/C++这里来。这样拿到①个指针p,并且想解引用的时候没有统①的方式判断p到p+①是否处于合法的空间内。
下面的例子,在Func函数中,不可能知道p开始的空间是谁创建的,Func(p+①⓪) VC debug不会出错,Func(&a)会报栈错误
void Func(int *p)
{
p[①] = ①⓪;
}
int main()
{
int *p = new int[①⓪];
Func(p + ①⓪);
int a, b;
Func(
return ⓪;
}
况且,VC栈错误也是在程序运行完之后报出来,对每个解引用都检查有效性代价太大
并且,不仅要对所有的指针检查,所有引用也要检查,每个指针/引用解引用每个元素的时候检查,比如下面a.x赋值正常,a.y赋值错误
void Func(A a.y = ②⓪;}int main(){A a;A *p = reinterpret_cast(Func(*p);return ⓪;}
原回答:
效率,release就是要快,对于每①个指针解引用都检查有效性是个巨大的开销,特别对于计算密集型程序
编后语:关于《关于c++中用extern引用的变量类型与定义类型不一致的一个疑问?C/C++主流编译器为什么样不做成debug模式编译的程序检查数组越界、溢出等错误》关于知识就介绍到这里,希望本站内容能让您有所收获,如有疑问可跟帖留言,值班小编第一时间回复。 下一篇内容是有关《小米note3实际体验如何?抛弃价格因素小米4c和红米note3谁更值得入手》,感兴趣的同学可以点击进去看看。
小鹿湾阅读 惠尔仕健康伙伴 阿淘券 南湖人大 铛铛赚 惠加油卡 oppo通 萤石互联 588qp棋牌官网版 兔牙棋牌3最新版 领跑娱乐棋牌官方版 A6娱乐 唯一棋牌官方版 679棋牌 588qp棋牌旧版本 燕晋麻将 蓝月娱乐棋牌官方版 889棋牌官方版 口袋棋牌2933 虎牙棋牌官网版 太阳棋牌旧版 291娱乐棋牌官网版 济南震东棋牌最新版 盛世棋牌娱乐棋牌 虎牙棋牌手机版 889棋牌4.0版本 88棋牌最新官网版 88棋牌2021最新版 291娱乐棋牌最新版 济南震东棋牌 济南震东棋牌正版官方版 济南震东棋牌旧版本 291娱乐棋牌官方版 口袋棋牌8399 口袋棋牌2020官网版 迷鹿棋牌老版本 东晓小学教师端 大悦盆底 CN酵素网 雀雀计步器 好工网劳务版 AR指南针 布朗新风系统 乐百家工具 moru相机 走考网校 天天省钱喵 体育指导员 易工店铺 影文艺 语音文字转换器