[C语言]

声明和定义问题 矛盾

[复制链接]
756|13
手机看帖
扫描二维码
随时随地手机跟帖
yanghelovehuang|  楼主 | 2018-8-29 13:37 | 显示全部楼层 |阅读模式
各位大神好,昨天我发了个帖子关于h文件里定义全局变量,其中有个大神说我声明和定义的概念混搅了,我一想确实这两个定义我不太明白,所以今天我查了一早上,可以说对他们俩有点了解了,但是我便写个程序和网上查的概念有点矛盾,求大神解释:
程序如图:
我在h文件里定义个全局变量 int a, 我再网上查的int a这种属于未初始化的定义,不属于声明,然后写了两个c文件操作它,之后编译运行都正确,没报错。
不是说h文件里不能定义全局变量吗?那我这种写法为什么没报错呢?还能运行出来结果?我有点乱,求大神结束。你们的回复我都会认真的看的,不会的我也回去查,因为我很感谢您们能回复。
Ubuntu-2018-08-29-13-30-51.png

相关帖子

Prry| | 2018-9-1 12:27 | 显示全部楼层
原则:头文件声明,源文件定义。千万不要头文件定义!

使用特权

评论回复
Prry| | 2018-9-1 12:36 | 显示全部楼层
多个文件引用了该头文件试试?

使用特权

评论回复
smartpower| | 2018-9-1 12:52 | 显示全部楼层
楼上正解~

使用特权

评论回复
john_lee| | 2018-9-1 14:05 | 显示全部楼层
  • 你把 test.h 中 的 int a; 改为 int a = 0; 或 int a __attribute__ ((section(".bss"))); 编译就会看见错误了。
  • 你把 sort 函数的那个 C 文件这样改一下:
    #include <stdio.h>
    #include "test.h"

    int b;

    void sort(void)
    {
            printf("*****************\n");

            a = 10;
            b = 1078530011;
    }

    main函数的 C 文件这样改一下:
    #include <stdio.h>
    #include "test.h"

    float b;
    void sort(void);

    int main(void)
    {
                    sort();
                    printf("a = %d, b = %f\n", a, b);
                    return 0;
    }

    编译运行,你会发现更奇怪的事。

使用特权

评论回复
Cjy_JDxy| | 2018-9-1 17:35 | 显示全部楼层
linux,厉害

使用特权

评论回复
yanghelovehuang|  楼主 | 2018-9-4 16:11 | 显示全部楼层
Prry 发表于 2018-9-1 12:36
多个文件引用了该头文件试试?

我查的结果是 在c语言中 像 int a 这种未初始化的变量 属于声明 您怎么看

使用特权

评论回复
yanghelovehuang|  楼主 | 2018-9-4 16:11 | 显示全部楼层
john_lee 发表于 2018-9-1 14:05
  • 你把 test.h 中 的 int a; 改为 int a = 0; 或 int a __attribute__ ((section(".bss"))); 编译就会看 ...

  • 您看下我回复楼上的 您的看法

    使用特权

    评论回复
    yanghelovehuang|  楼主 | 2018-9-4 16:17 | 显示全部楼层
    john_lee 发表于 2018-9-1 14:05
  • 你把 test.h 中 的 int a; 改为 int a = 0; 或 int a __attribute__ ((section(".bss"))); 编译就会看 ...

  • 确实奇怪 这是为什么啊? 我以为是强制转换呢 试了下不是

    使用特权

    评论回复
    Prry| | 2018-9-4 21:54 | 显示全部楼层
    yanghelovehuang 发表于 2018-9-4 16:11
    我查的结果是 在c语言中 像 int a 这种未初始化的变量 属于声明 您怎么看

    属于定义,找个编译器测试下就知道了。看一百遍书,不如敲一行代码。

    使用特权

    评论回复
    john_lee| | 2018-9-4 23:42 | 显示全部楼层
    C 语言标准中有个术语叫 tentative definition,中文翻译为“尝试性定义”,一般具有外部连接属性的未初始化全局变量,都是尝试性定义。
    例如:

    int a;                                 // 是尝试性定义
    char b[20];                    // 是尝试性定义
    int c = 0;                          // 已初始化,不是尝试性定义
    static int d;                    // 只有本文件作用域,不具有外部连接属性,不是尝试性定义
    void foo(void)
    {
            int e;                          // 局部变量,不是尝试性定义
            static int f;              // 静态局部变量,不具有外部连接属性,不是尝试性定义
            ...
    }

    关于目标文件中变量的链接情况,分为以下三种:

    • 当多个目标文件存在相同名称的尝试性变量,链接程序会从中选择一个最大的 size,以这个 size 为该变量分配存储,并将所有相同名称的尝试性变量都链接到这个存储地址。
      注:编译后的目标文件中是没有变量的类型信息的。
      例如:
      // file1.c
      int a;                                // 尝试性定义变量
      void foo(void)
      {
              a = 0x34333231;
      }
      // file2.c
      #include <stdio.h>
      char a[5];                          // 尝试性定义变量
      void foo(void);
      int main(void)
      {
              foo();
              a[4] = '\0';
              printf("%s\n", a);
      }
      在该例中,两个 C 文件都定义了名称为 a 的变量,大小和类型都不同,编译后,类型信息丢失,目标文件中只有变量的名称和大小信息,链接程序会选择较大的大小(file2.c 中定义的 5 字节),作为实际的变量大小。
    • 当某一个目标文件存在已初始化的变量,而其它目标文件存在该变量同名的尝试性变量,则链接程序会使用已初始化的变量的大小为该变量分配存储,并将所有相同名称的尝试性变量都链接到这个存储地址。
      注意:如果尝试性变量的大小超过了已初始化的变量大小,程序中对尝试性变量的访问肯定会越界。
    • 当多个目标文件存在同名的已初始化的变量,则链接程序报错。

    使用特权

    评论回复
    yanghelovehuang|  楼主 | 2018-9-5 09:26 | 显示全部楼层
    john_lee 发表于 2018-9-4 23:42
    C 语言标准中有个术语叫 tentative definition,中文翻译为“尝试性定义”,一般具有外部连接属性的未初始 ...

    谢谢您的回复 很详细,我大概了解了,c语言中未初始化变量具有外部链接功能,学习了 辛苦您了 谢谢

    使用特权

    评论回复
    yanghelovehuang|  楼主 | 2018-9-5 09:29 | 显示全部楼层
    Prry 发表于 2018-9-4 21:54
    属于定义,找个编译器测试下就知道了。看一百遍书,不如敲一行代码。

    请问该怎么测试啊,我上面写的代码其实就是测试int a是不是声明的。

    使用特权

    评论回复
    Ketose| | 2018-9-5 10:02 | 显示全部楼层
    在.h文件里定义变量,如果很多.c文件引用这个头文件的时候,编译就会报重复定义变量的错误。

    使用特权

    评论回复
    发新帖 我要提问
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    156

    主题

    324

    帖子

    1

    粉丝