[C语言] 声明和定义问题 矛盾

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
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 文件这样改一下:
    1. #include <stdio.h>
    2. #include "test.h"

    3. int b;

    4. void sort(void)
    5. {
    6.         printf("*****************\n");

    7.         a = 10;
    8.         b = 1078530011;
    9. }
    复制代码

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

    3. float b;
    4. void sort(void);

    5. int main(void)
    6. {
    7.                 sort();
    8.                 printf("a = %d, b = %f\n", a, b);
    9.                 return 0;
    10. }
    复制代码

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

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,中文翻译为“尝试性定义”,一般具有外部连接属性的未初始化全局变量,都是尝试性定义。
    例如:

    1. int a;                                 // 是尝试性定义
    2. char b[20];                    // 是尝试性定义
    3. int c = 0;                          // 已初始化,不是尝试性定义
    4. static int d;                    // 只有本文件作用域,不具有外部连接属性,不是尝试性定义
    5. void foo(void)
    6. {
    7.         int e;                          // 局部变量,不是尝试性定义
    8.         static int f;              // 静态局部变量,不具有外部连接属性,不是尝试性定义
    9.         ...
    10. }
    复制代码

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

    • 当多个目标文件存在相同名称的尝试性变量,链接程序会从中选择一个最大的 size,以这个 size 为该变量分配存储,并将所有相同名称的尝试性变量都链接到这个存储地址。
      注:编译后的目标文件中是没有变量的类型信息的。
      例如:
      1. // file1.c
      2. int a;                                // 尝试性定义变量
      3. void foo(void)
      4. {
      5.         a = 0x34333231;
      6. }
      复制代码
      1. // file2.c
      2. #include <stdio.h>
      3. char a[5];                          // 尝试性定义变量
      4. void foo(void);
      5. int main(void)
      6. {
      7.         foo();
      8.         a[4] = '\0';
      9.         printf("%s\n", a);
      10. }
      复制代码
      在该例中,两个 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

    粉丝
    快速回复 在线客服 返回列表 返回顶部