C:Var和Function有相同的名字 - ld的错误?

时间:2015-05-14 13:43:25

标签: c gcc linker

在我的项目(https://github.com/zzt93/os-lab1)中,我遇到一个全局变量与一个函数具有相同的名称,但是在错误或警告的情况下编译它会产生错误。

一个简单的程序几乎可以重现这个问题:

 //a.c
 struct {
     int t;
     int *s;
 } empty, full;

 int main(){
     printf("full is at %p", &full);
     printf("empty is at %p", &empty);
     empty.t = 1;
     return 0;
 }


 //b.c
 int empty() {
     return 1;
 }

使用gcc -o res.out -Wall -g -Wextra a.c b.c编译它们 只会产生这样的警告(通知:在我的项目中,它甚至不会产生错误):

  

/ usr / bin / ld:警告:/tmp/ccq70SCM.o中符号empty的对齐1在/tmp/ccVCOeWq.o中小于16

     

/ usr / bin / ld:警告:符号empty的大小从/tmp/ccVCOeWq.o中的16更改为/tmp/ccq70SCM.o中的11

     

/ usr / bin / ld:警告:/tmp/ccq70SCM.o中符号empty的类型从1更改为2

似乎需要struct emptyfunction empty作为同一个。

反编译它,您可以清楚地看到链接器链接function empty的地址而不是struct empty。所以尝试运行res.out会导致段错误。

  40054e:   be 73 05 40 00          mov    $0x400573,%esi
  400553:   bf 12 06 40 00          mov    $0x400612,%edi
  400558:   b8 00 00 00 00          mov    $0x0,%eax
  40055d:   e8 ae fe ff ff          callq  400410 <printf@plt>
  400562:   c7 05 07 00 00 00 01    movl   $0x1,0x7(%rip)            # 400573 <empty>
  400569:   00 00 00 
  40056c:   b8 00 00 00 00          mov    $0x0,%eax
  400571:   5d                      pop    %rbp
  400572:   c3                      retq   

0000000000400573 <empty>:
  400573:   55                      push   %rbp
  400574:   48 89 e5                mov    %rsp,%rbp
  400577:   b8 01 00 00 00          mov    $0x1,%eax
  40057c:   5d                      pop    %rbp
  40057d:   c3                      retq   
  40057e:   66 90                   xchg   %ax,%ax

问题:

为什么链接器选择函数而不是结构?我认为这是一个错误吗?

为什么为struct的声明添加一个静态可以防止这个错误? - 我们了解static使该变量在此文件外部不可见,但请注意我向struct empty添加静态而非function empty 解决问题。

修改: 奇怪的是,在res.out的符号表中,只有一个empty

Name                  Value           Class        Type         Size             Line  Section
empty               |0000000000400573|   T  |              FUNC|000000000000000b|     |.text

我正在使用

  

gcc version 4.9.2

1 个答案:

答案 0 :(得分:4)

添加static可以防止错误,因为static在应用于函数或全局变量时会使符号不会导出到链接器 - 简单来说,它使它对该文件“私有”

如果不使用static,链接器将看到两个定义,但类型不匹配。但是,由于编译是逐个文件应用的,因此链接器无法知道正确的变量类型 - 它必须相信您完成了工作并且没有说谎。

这就是头文件很重要的原因 - 它确保类型在不同的文件中匹配。