当前位置:  开发笔记 > 编程语言 > 正文

在C vs C++中由编译器在目标文件中包含未使用的符号

如何解决《在CvsC++中由编译器在目标文件中包含未使用的符号》经验,为你挑选了1个好方法。

这可能是一个愚蠢的问题,但也许有人可以提供一些见解.

我在头文件中定义了一些全局变量(是的,我知道这很糟糕,但这只是一种假设情况).我将此头文件包含在两个源文件中,然后将这些文件编译为两个目标文件.全局符号不会在代码中的任何位置引用.

如果源文件是C,那么看起来编译器省略了全局符号,并且所有链接都没有错误.如果源文件是C++,则符号包含在两个目标文件中,然后我会收到链接器错误.对于C++,当我包含标题时,我使用extern"C".

我正在使用VS2005的Microsoft编译器.

这是我的代码:

头文件(test.h):

#ifndef __TEST_H
#define __TEST_H

/* declaration in header file */
void *ptr;

#endif

C源文件:

test1.c

#include "test.h"

int main( ) {
    return 0;
}

test2.c中

#include "test.h"

C++源文件:

test1.cpp

extern "C" {
#include "test.h"
}

int main( ) {
    return 0;
}

测试2.cpp

extern "C" {
#include "test.h"
}

对于C,目标文件看起来像这样:

Dump of file test1.obj

File Type: COFF OBJECT

COFF SYMBOL TABLE
000 006DC627 ABS    notype       Static       | @comp.id
001 00000001 ABS    notype       Static       | @feat.00
002 00000000 SECT1  notype       Static       | .drectve
    Section length   2F, #relocs    0, #linenums    0, checksum        0
004 00000000 SECT2  notype       Static       | .debug$S
    Section length  228, #relocs    7, #linenums    0, checksum        0
006 00000004 UNDEF  notype       External     | _ptr
007 00000000 SECT3  notype       Static       | .text
    Section length    7, #relocs    0, #linenums    0, checksum 96F779C9
009 00000000 SECT3  notype ()    External     | _main
00A 00000000 SECT4  notype       Static       | .debug$T
    Section length   1C, #relocs    0, #linenums    0, checksum        0

String Table Size = 0x0 bytes

对于C++,它们看起来像这样:

Dump of file test1.obj

File Type: COFF OBJECT

COFF SYMBOL TABLE
000 006EC627 ABS    notype       Static       | @comp.id
001 00000001 ABS    notype       Static       | @feat.00
002 00000000 SECT1  notype       Static       | .drectve
    Section length   2F, #relocs    0, #linenums    0, checksum        0
004 00000000 SECT2  notype       Static       | .debug$S
    Section length  228, #relocs    7, #linenums    0, checksum        0
006 00000000 SECT3  notype       Static       | .bss
    Section length    4, #relocs    0, #linenums    0, checksum        0
008 00000000 SECT3  notype       External     | _ptr
009 00000000 SECT4  notype       Static       | .text
    Section length    7, #relocs    0, #linenums    0, checksum 96F779C9
00B 00000000 SECT4  notype ()    External     | _main
00C 00000000 SECT5  notype       Static       | .debug$T
    Section length   1C, #relocs    0, #linenums    0, checksum        0

String Table Size = 0x0 bytes

我注意到_ptr在编译C源时被列为UNDEF,并且在编译C++源时定义它,这会导致链接器错误.

我知道这在现实生活中不是一件好事,我只是想了解为什么这是不同的.

谢谢.



1> Alok Singhal..:

在C中,标识符有三种不同类型的"链接":

    外部联系:粗略地说,这就是人们对"全局变量"的意思.通常,它指的是"无处不在"可见的标识符.

    内部链接:这些是使用static关键字声明的对象.

    无链接:这些是"临时"或"自动"的对象,例如在函数内声明的变量(通常称为"局部变量").

对于具有外部链接的对象,您只能有一个定义.由于您的头文件定义了这样一个对象并包含在两个C文件中,因此它是未定义的行为(但见下文).您的C编译器没有抱怨的事实并不意味着在C中这样做是可以的.为此,您必须阅读C标准.(或者,假设您的编译器中没有错误,如果它是在符合标准的模式下调用的,并且如果它抱怨[给出诊断],则可能意味着您的程序不符合.)

换句话说,您无法通过测试某些内容并检查编译器是否允许来测试该语言允许的内容.为此,您必须阅读标准.

请注意,定义和暂定定义之间存在细微差别.

$ cat a.c
int x = 0;
$ cat b.c
#include 
int x = 0;
int main(void)
{
    printf("%d\n", x);
    return 0;
}
$ gcc -ansi -pedantic -W -Wall -c a.c
$ gcc -ansi -pedantic -W -Wall -c b.c
$ gcc -o def a.o b.o
b.o:(.bss+0x0): multiple definition of `x'
a.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status

现在,让我们改变a.c:

$ cat a.c
int x; /* Note missing " = 0", so tentative definition */

现在编译它:

$ gcc -ansi -pedantic -W -Wall -c a.c
$ gcc -o def a.o b.o
$ ./def
0

我们可以改变b.c:

$ cat a.c
int x = 0;
$ cat b.c
#include 
int x; /* tentative definition */
int main(void)
{
    printf("%d\n", x);
    return 0;
}
$ gcc -ansi -pedantic -W -Wall -c a.c
$ gcc -ansi -pedantic -W -Wall -c b.c
$ gcc -o def a.o b.o
$ ./def
0

如果没有其他定义,"暂定"将成为C中的"真实定义".所以,我们可以更改两个文件以包含int x;,这将是合法的C.

因此,您可能在头文件中有一个暂定的定义.我们需要确定实际的代码.

C标准说以下是未定义的行为(附录J.2p1):

使用具有外部链接的标识符,但是在程序中,不存在标识符的正好一个外部定义,或者不使用标识符,并且标识符存在多个外部定义.

C++可能有不同的规则.

编辑:根据此线程comp.lang.c++,C++没有暂定定义.原因是:

这避免了对内置类型和用户定义类型的不同初始化规则.

(线程处理相同的问题,顺便说一句.)

现在我几乎可以肯定OP的代码包含C在头文件中称为"暂定定义"的内容,这使得它在C语言中是合法的并且在C++中是非法的.只有当我们看到代码时,我们才会确定.

有关"暂定定义"及其原因的更多信息,请参阅comp.lang.c(Chris Torek)的优秀文章.

推荐阅读
路人甲
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有