c语言 - 为什么使用在 File1 中定义的数组在 File2 中工作(仅在那里声明),即使没有"extern"?



这里我有两个文件externdemo1.cexterndemo2.c .在第一个文件中,我已经声明并初始化了一个字符数组arr在文件作用域。但是我在第二个文件externdemo2.c中声明了它,没有extern关键字,并在函数display()中使用了它。以下是我由此产生的困惑。请回答这三个问题:

 //File No.1--externdemo1.c
#include<stdio.h>
#include "externdemo2.c"
extern int display();
char arr[3]={'3','4','7'};
//extern char arr[3]={'3','4','7'};
//extern int main()
int main()
{
    printf("%d",display());
}

//File No.2--externdemo2.c
char arr[3];
int display()
{
    return sizeof(arr);
}

1)为什么程序编译良好,即使我已经声明了arr没有extern关键字在externdemo2.c ?我读到函数的默认链接是外部的,但我不确定如果是这样,即使是变量。我只知道全局变量有extern存储类。

2) extern storage classextern linkage的严格区别是什么?我迫切需要澄清这一点。在第一个文件中,我定义了数组arr,我没有使用关键字extern,但我知道它默认具有extern storage类。但是在第二个文件中,是否有任何默认的extern,存储类或链接,关于全局变量arr,即在externdemo2.c中?

3)检查第一个文件externdemo1.c中的注释行。只是为了测试它,我使用了extern char arr[3]={'3','4','7'};行,但是它给出了错误'arr' initialized and declared 'extern'。这个错误意味着什么?我还提到了一个注释行extern int main(),但它工作得很好,没有错误或警告。那么,为什么我们可以在函数中使用extern,即使函数默认是extern,但不能用于变量,比如这里的arr ?

请花点时间帮我解决这件事。它将消除我对整个extern事件的大部分挥之不去的疑虑。这将是巨大的帮助,如果你能回答所有3位1),2)和3)Especially 3) is eating my brains out

主要问题

  1. 基本上,因为您已经在externdemo1.c文件中包含了externdemo2.c的源代码。

  2. 这是一个大问题。因为没有初始化式,所以externdemo2.c中的char arr[3];行生成数组arr的暂定定义。当遇到具有初始化的实际定义时,暂定定义不再是暂定定义,但也不是重复定义。

    关于extern storage class vs extern linkage…链接是指是否可以从定义符号的源文件外部看到符号。具有extern linkage的符号可以被其他正确声明该符号的源文件通过名称访问。在定义的范围内,extern storage class表示"存储在函数作用域之外",因此独立于任何函数。使用exn存储类定义的变量可能有外部链接,也可能没有。

    因为没有使用关键字static定义,所以数组arr具有外部链接;

  3. 注释掉的行没有注释掉,你有一个数组的两个定义,这是不允许的。

我观察到你必须只编译externdemo1.c来创建一个程序——编译器包含了externdemo2.c的代码,因为它是直接包含的。您可以从externdemo2.c创建一个对象文件。但是,您不能通过链接externdemo1.cexterndemo2.c的目标文件来创建程序,因为这会导致函数display()的多个定义。

辅助问题

我已经把两个文件放在[同一个目录]了。如果我没有在第一个文件中包含第二个文件,那么当我编译第一个文件时,它会显示错误undefined reference。因为我在第一个文件中使用了extern函数,即使我不包括第二个文件,链接器也不应该链接到它吗?或者链接器只在默认文件夹中查找?

这里有几个混淆。让我们试着一个一个地解决它们。

链接器(通常由编译器启动)将链接命令行中指定的目标文件和库。如果您想要两个目标文件,将它们称为externdemo1.objexterndemo2.obj,链接在一起,您必须告诉链接器(通过IDE中的构建系统)它需要处理这两个目标文件-以及默认情况下不拾取的任何库。(标准C库,加上特定于平台的扩展,通常会自动拾取,除非您特意阻止这种情况发生。)

链接器没有义务花任何时间寻找可能满足引用的零散目标文件;实际上,期望它只链接那些被告知要链接的目标文件和库,而不是随意添加其他文件和库。这里有一些关于库的警告(如果一个库被告知要链接,它可能会添加一些没有在命令行中提到的库),但是链接器不会添加额外的对象文件。

c++与模板实例化的

可能被认为有点不同,但实际上它遵循了大致相同的规则。

源代码

你应该有一个标题,externdemo.h,它包含:

#ifndef EXTERNDEMO_H_INCLUDED
#define EXTERNDEMO_H_INCLUDED
extern int display(void);
extern char arr[3];  // Or extern char arr[]; -- but NOT extern char *arr;
#endif /* EXTERNDEMO_H_INCLUDED */

您应该修改源文件以包含头文件:

//File No.1--externdemo1.c
#include <stdio.h>
#include "externdemo.h"
char arr[3] = { '3', '4', '7' };
int main(void)
{
    printf("%dn", display());
    return 0;
}

:

//File No.2--externdemo2.c
#include "externdemo.h"
int display(void)
{
    return sizeof(arr);
}

唯一棘手的问题是"externdemo2.c真的知道arr的大小吗?"答案是"是的"(至少在Mac OS X 10.8.3上使用GCC 4.7.1)。但是,如果头文件中的extern声明没有包含size (extern char arr[];),则会得到如下编译错误:

externdemo2.c: In function ‘display’:
externdemo2.c:7:18: error: invalid application of ‘sizeof’ to incomplete type ‘char[]’
externdemo2.c:8:1: warning: control reaches end of non-void function [-Wreturn-type]

您的程序看起来有点错误。对我来说,#include "externdemo2.c"行无效。

以下是我所做的更正,它有效。

    //File No.1--externdemo1.c
    #include <stdio.h>
    extern char arr[3];
    extern int display();
    int main()
    {
        printf("%d", arr[0]);
        printf("%d",display());
    }
    //File No.2--externdemo2.c

    char arr[3]={'3','4','7'};
    int display()
    {
        return sizeof(arr);
    }

请点击以下链接以便更好地理解:

    extern关键字对C函数的影响
  • 如何使用extern在源文件之间共享变量?

使用#include将使这两个文件仅作为一个文件。可以使用标志-E检查中间文件,如下所示:

gcc -E externdemo1.c

相关内容

  • 没有找到相关文章

最新更新