相同指针与全局变量编译之坑

大耗子 2020年11月27日 80次浏览

相同指针陷阱

这是一个将yp指针的值加到xp指针两次的函数。

void fun1(int *xp, int *yp)
{
	*xp += *yp;
	*xp += *yp;
}

这个代码表面一看可以优化成这样

void fun1(int *xp, int *yp)
{
	*xp += 2 * *yp;
}

但是如果yp于xp指针指向的是同一个地址,那么情况就会变成这样,此时*xp的结果会是原先的4倍。

void fun1(int *xp, int *yp)
{
	*xp += *xp;
	*xp += *xp;
}

修改了后会变成这样,结果只是原先的三倍。

void fun1(int *xp, int *yp)
{
	*xp += 2 * *xp;
}

全局变量声明陷阱

  • 在编译时,编译器向汇编器输出每个全局符号,或者强或弱,而汇编器把这个信息隐含地编码在可重定位目标文件的符号表里。函数和已初始化的全局变量是强符号,未初始化的全局变量是弱符号

Linux链接器通过下面的规则来处理多重定义的符号名:

  1. 不允许有多个同名的强符号。
  2. 如果有一个强符号和多个弱符号同名,那么选择强符号。
  3. 如果有多个弱符号同名,那么从这些弱符号中任选一个。

例如,假设我们试图编译和链接下面两个C模块。

/*foo1.c*/
int main()
{
	return 0;
}

/*bar1.c*/
int main()
{
	return 0;
}
  • 这种情况中,连接器一定会生成一条错误信息,因为强符号main被定义了多次。

  • 相似的,如果是已初始化的全局变量也会报重定义。

/*foo1.c*/
int x = 20201127;
int main()
{
	return 0;
}

/*bar1.c*/
int x = 20201128;
int main()
{
	return 0;
}
  • 但是如果有其中一个文件中的同名全局变量没有初始化,那么强全局变量只有一个,编译是可以通过的,这时候编译器只会报警告。
  • 如果是一个模块极其庞大的程序,检查起来更加困难,会造成不可预料的后果。
  • 甚至有可能全局变量名字一样,但是类型不一样,这出现问题起来,更加的危险。
/*foo1.c*/
int x = 20201127;
int main()
{
	return 0;
}

/*bar1.c*/
int x;
int main()
{
	return 0;
}