对C中的目标文件未使用的符号由编译器在C ++纳入 [英] Inclusion of unused symbols in object files by compiler in C vs C++

查看:129
本文介绍了对C中的目标文件未使用的符号由编译器在C ++纳入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

This might be a dumb question, but maybe someone can provide some insight.

我(是的是的,我知道这是很糟糕,但是这仅仅是一个假设的情况),在头文件中定义了一些全局变量。我包括两个源文件,然后将其编译成两个目标文件这个头文件。全局符号未在code的任何地方引用。

I have some global variables defined in a header file (yes yes I know that's bad, but this is just a hypothetical situation). I include this header file in two source files, which are then compiled into two object files. The global symbols are not referenced anywhere in the code.

如果源文件是C,那么它看起来像编译器忽略没有错误的全局符号和一切联系。如果源文件是C ++,符号都包含在这两个目标文件,然后我得到的链接错误。对于C ++我使用的externC当我包含头。

If the source files are C, then it looks like the compiler omits the global symbols and everything links without errors. If the source files are C++, the symbols are included in both object files and then I get linker errors. For C++ I am using extern "C" when I include the header.

我使用VS2005从微软编译器。

I am using the Microsoft compiler from VS2005.

下面是我的code:

头文件(test.h):

Header file (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中

test2.c

#include "test.h"

C ++源文件:

C++ Source Files:

test1.cpp

test1.cpp

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

int main( ) {
    return 0;
}

测试2.cpp

test2.cpp

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

有关C,将目标文件看起来像这样:

For C, the object files look something like this:

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 ++的,他们是这个样子:

And for C++ they look something like this:

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源代码,当我编译C ++源代码,这会导致链接错误它被定义。

I notice that _ptr is listed as UNDEF when I compile the C source, and it is defined when I compile the C++ source, which results in linker errors.

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

I understand that this is not a good thing to do in real life, I am just trying to understand why this is different.

感谢。

推荐答案

在C,标识符有三种不同类型的联动:

In C, identifiers have three different types of "linkage":


  1. 外部链接的:大概,这就是人们的全局变量的意思。在常用术语,它指的是可见的无处不在的标识符。

  2. 内部链接的:这些都是被宣布与静态关键字对象

  3. 没有任何联系的:这些对象是暂时的,或自动,如功能(通常称为局部变量)内声明的变量

  1. external linkage: roughly, this is what people mean by "global variables". In common terms, it refers to identifiers that are visible "everywhere".
  2. internal linkage: these are objects that are declared with static keyword.
  3. no linkage: these are objects that are "temporary", or "automatic", such as variables declared inside a function (commonly referred as "local variables").

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

For objects with external linkage, you can have only one definition. Since your header file defines such an object and is included in two C files, it is undefined behavior (but see below). The fact that your C compiler doesn't complain does not mean it is OK to do so in C. For this, you must read the C standard. (Or, assuming no bugs in your compiler, if it is invoked in a standards-compliant mode, and if it complains about something [gives a diagnostic], it probably means your program isn't compliant.)

在换句话说,你不能测试的是什么语言允许通过测试的东西和检查,如果你的编译器允许它。对于这一点,你必须阅读的标准。

In other words, you can't test what is allowed by the language by testing something and checking if your compiler allows it. For this, you must read the standard.

请注意,有定义之间的细微差别和暂定的定义。

Note that there is a subtle difference between definition and tentative definition.

$ cat a.c
int x = 0;
$ cat b.c
#include <stdio.h>
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

现在,让我们改变交流转换器

$ 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 <stdio.h>
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

A "tentative definition" becomes "real definition" in C if there is no other definition. So, we could have changed both files to contain int x;, and it would be legal C.

所以,你可能会在头文件中的暂定定义。我们需要看到实际的code是肯定的。

So, you may have a tentative definition in the header file. We need to see the actual code to be sure.

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

The C standard says that the following is undefined behavior (appendix J.2p1):

与外部连接的标识符被使用,但在节目不存在
  究竟是不用于标识符或标识符一个外部定义并有
  存在多个外部定义的标识符。

An identifier with external linkage is used, but in the program there does not exist exactly one external definition for the identifier, or the identifier is not used and there exist multiple external definitions for the identifier.

C ++可以有不同的规则。

C++ may have different rules.

修改的:按照 comp.lang.c ++ 这个线程,C ++不具备的暂定定义的。其原因是:

Edit: As per this thread on comp.lang.c++, C++ does not have tentative definitions. The reason being:

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

This avoids having different initialization rules for built-in types and user-defined types.

(同样的问题,顺便说一句线程的交易。)

(The thread deals with the same question, btw.)

现在,我几乎可以肯定,OP的code包含什么C所谓的暂定定义中的头文件,这使得在C合法和非法的在C ++中。我们将肯定知道只有当我们虽然看到了code。

Now I am almost sure that OP's code contains what C calls "tentative definition" in the header file, which makes it legal in C and illegal in C++. We will know for sure only when we see the code though.

在暂定定义,为什么他们都需要在此的优秀的职位上comp.lang.c (克里斯托雷克)。

More information on "tentative definitions" and why they are needed is in this excellent post on comp.lang.c (by Chris Torek).

这篇关于对C中的目标文件未使用的符号由编译器在C ++纳入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆