鱼C论坛

 找回密码
 立即注册
查看: 2169|回复: 20

[已解决]关于结构体的默认初始化问题

[复制链接]
发表于 2022-11-25 22:09:23 | 显示全部楼层 |阅读模式
60鱼币
本帖最后由 孤不冷cing 于 2022-11-26 19:14 编辑

看了大佬们的回复,感觉自己C的门还没摸到,任重而道远啊
$ cat test3.c
#include <stdio.h>

struct Imfor{
        char *name;
};

int main(void)
{
        struct Imfor imfor;

        if (imfor.name == NULL)
                printf("imfor.name == NULL\n");

        return 0;
}
$ gcc test3.c -o test3 && ./test3
imfor.name == NULL
$ cat test4.c
#include <stdio.h>

struct Imfor{
        char name[10];
};

int main(void)
{
        struct Imfor imfor;

        if (imfor.name == NULL)
        {
                printf("imfor.name == NULL\n");
        }
        else if (imfor.name[0] == '\0')
        {
                printf("imfor.name[0] == '\\0'\n");
        }

        return 0;
}
$ gcc test4.c -o test4 && ./test4
imfor.name[0] == '\0'

在小甲鱼的C教程里说,未初始化的会自动初始化为'\0',为什么字符指针是初始化为NULL啊
结构体中其他类型的变量又会初始化成什么呢
最佳答案
2022-11-25 22:09:24
本帖最后由 jackz007 于 2022-11-26 10:56 编辑

        分别用 gcc 和 VC9.0 编译下面的代码,研究一下反汇编代码,看看是否真的有变量的初始化
#include <stdio.h>

int main(void)
{
        struct node {
                int i               ;
                int * p             ;
        } dx                        ;
        printf("i = %d\n" , dx . i) ;
        printf("p = %p\n" , dx . p) ;
}
       【tdm-gcc 5.1.0】:
00401350  /$  55                         push    ebp                                   main() 入口
00401351  |.  89E5                       mov     ebp, esp
00401353  |.  83E4 F0                    and     esp, FFFFFFF0
00401356  |.  83EC 20                    sub     esp, 20                               <--- 堆栈分配 0x20 字节供局部变量使用
00401359  |.  E8 E2050000                call    00401940                                            
0040135E  |.  8B4424 18                  mov     eax, dword ptr [esp+18]               <--- dx . i - 直接使用,未经任何初始化
00401362  |.  894424 04                  mov     dword ptr [esp+4], eax                <--- dx . i 入栈,准备显示
00401366  |.  C70424 24304000            mov     dword ptr [esp], 00403024             ; ||ASCII "i = %d"
0040136D  |.  E8 3E080000                call    <jmp.&msvcrt.printf>                  ; |\printf()
00401372  |.  8B4424 1C                  mov     eax, dword ptr [esp+1C]               <--- dx . p - 直接使用,未经任何初始化                            
00401376  |.  894424 04                  mov     dword ptr [esp+4], eax                <--- dx . p 入栈,准备显示                             
0040137A  |.  C70424 2C304000            mov     dword ptr [esp], 0040302C             ; |ASCII "p = %p"
00401381  |.  E8 2A080000                call    <jmp.&msvcrt.printf>                  ; \printf()
00401386  |.  B8 00000000                mov     eax, 0
0040138B  |.  C9                         leave
0040138C  \.  C3                         retn
        【VC9.0】
00401000  /$  55                         push    ebp                                   main() 入口
00401001  |.  8BEC                       mov     ebp, esp
00401003  |.  83EC 08                    sub     esp, 8                                <--- 堆栈分配 0x08 字节供局部变量使用
00401006  |.  8B45 F8                    mov     eax, dword ptr [ebp-8]                dx . i - 直接使用,未经任何初始化
00401009  |.  50                         push    eax                                   <--- dx . i 入栈,准备显示
0040100A  |.  68 00C04000                push    0040C000                              ;  ASCII "i = %d"
0040100F  |.  E8 1A000000                call    0040102E                              <--- printf()
00401014  |.  83C4 08                    add     esp, 8
00401017  |.  8B4D FC                    mov     ecx, dword ptr [ebp-4]                <--- dx . p - 直接使用,未经任何初始化
0040101A  |.  51                         push    ecx                                   <--- dx . p 入栈,准备显示
0040101B  |.  68 08C04000                push    0040C008                              ;  ASCII "p = %p"
00401020  |.  E8 09000000                call    0040102E                              <--- printf()
00401025  |.  83C4 08                    add     esp, 8
00401028  |.  33C0                       xor     eax, eax
0040102A  |.  8BE5                       mov     esp, ebp
0040102C  |.  5D                         pop     ebp
0040102D  \.  C3                         retn
        最后结论就是,不要想太多,编译器绝对不会为你初始化任何一个变量

最佳答案

查看完整内容

分别用 gcc 和 VC9.0 编译下面的代码,研究一下反汇编代码,看看是否真的有变量的初始化 【tdm-gcc 5.1.0】: 【VC9.0】 最后结论就是,不要想太多,编译器绝对不会为你初始化任何一个变量
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-25 22:09:24 | 显示全部楼层    本楼为最佳答案   
本帖最后由 jackz007 于 2022-11-26 10:56 编辑

        分别用 gcc 和 VC9.0 编译下面的代码,研究一下反汇编代码,看看是否真的有变量的初始化
#include <stdio.h>

int main(void)
{
        struct node {
                int i               ;
                int * p             ;
        } dx                        ;
        printf("i = %d\n" , dx . i) ;
        printf("p = %p\n" , dx . p) ;
}
       【tdm-gcc 5.1.0】:
00401350  /$  55                         push    ebp                                   main() 入口
00401351  |.  89E5                       mov     ebp, esp
00401353  |.  83E4 F0                    and     esp, FFFFFFF0
00401356  |.  83EC 20                    sub     esp, 20                               <--- 堆栈分配 0x20 字节供局部变量使用
00401359  |.  E8 E2050000                call    00401940                                            
0040135E  |.  8B4424 18                  mov     eax, dword ptr [esp+18]               <--- dx . i - 直接使用,未经任何初始化
00401362  |.  894424 04                  mov     dword ptr [esp+4], eax                <--- dx . i 入栈,准备显示
00401366  |.  C70424 24304000            mov     dword ptr [esp], 00403024             ; ||ASCII "i = %d"
0040136D  |.  E8 3E080000                call    <jmp.&msvcrt.printf>                  ; |\printf()
00401372  |.  8B4424 1C                  mov     eax, dword ptr [esp+1C]               <--- dx . p - 直接使用,未经任何初始化                            
00401376  |.  894424 04                  mov     dword ptr [esp+4], eax                <--- dx . p 入栈,准备显示                             
0040137A  |.  C70424 2C304000            mov     dword ptr [esp], 0040302C             ; |ASCII "p = %p"
00401381  |.  E8 2A080000                call    <jmp.&msvcrt.printf>                  ; \printf()
00401386  |.  B8 00000000                mov     eax, 0
0040138B  |.  C9                         leave
0040138C  \.  C3                         retn
        【VC9.0】
00401000  /$  55                         push    ebp                                   main() 入口
00401001  |.  8BEC                       mov     ebp, esp
00401003  |.  83EC 08                    sub     esp, 8                                <--- 堆栈分配 0x08 字节供局部变量使用
00401006  |.  8B45 F8                    mov     eax, dword ptr [ebp-8]                dx . i - 直接使用,未经任何初始化
00401009  |.  50                         push    eax                                   <--- dx . i 入栈,准备显示
0040100A  |.  68 00C04000                push    0040C000                              ;  ASCII "i = %d"
0040100F  |.  E8 1A000000                call    0040102E                              <--- printf()
00401014  |.  83C4 08                    add     esp, 8
00401017  |.  8B4D FC                    mov     ecx, dword ptr [ebp-4]                <--- dx . p - 直接使用,未经任何初始化
0040101A  |.  51                         push    ecx                                   <--- dx . p 入栈,准备显示
0040101B  |.  68 08C04000                push    0040C008                              ;  ASCII "p = %p"
00401020  |.  E8 09000000                call    0040102E                              <--- printf()
00401025  |.  83C4 08                    add     esp, 8
00401028  |.  33C0                       xor     eax, eax
0040102A  |.  8BE5                       mov     esp, ebp
0040102C  |.  5D                         pop     ebp
0040102D  \.  C3                         retn
        最后结论就是,不要想太多,编译器绝对不会为你初始化任何一个变量

评分

参与人数 2荣誉 +10 鱼币 +10 贡献 +6 收起 理由
孤不冷cing + 5 + 5 + 3 鱼C有你更精彩^_^
竹逸 + 5 + 5 + 3 鱼C有你更精彩^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-25 22:23:58 | 显示全部楼层
第1个代码如果你开了编译器警告的话,编译器会给你一个这样的警告
为什么编译器会给你这个警告呢?这个警告是什么意思?
main.c: In function ‘main’:
main.c:11:18: warning: ‘imfor.name’ is used uninitialized [-Wuninitialized]
   11 |         if (imfor.name == NULL)
      |             ~~~~~^~~~~
main.c:9:22: note: ‘imfor’ declared here
    9 |         struct Imfor imfor;
      |                      ^~~~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-25 22:25:36 | 显示全部楼层
上面的代码中的警告和这个一样,你说这样的代码有什么问题呢?
sh-5.1$ cat main.c
#include <stdio.h>

int main(void) {
    int i;
    printf("%d\n", i);
    return 0;
}
sh-5.1$ gcc -g -Wall -o main main.c
main.c: In function ‘main’:
main.c:5:5: warning: ‘i’ is used uninitialized [-Wuninitialized]
    5 |     printf("%d\n", i);
      |     ^~~~~~~~~~~~~~~~~
main.c:4:9: note: ‘i’ was declared here
    4 |     int i;
      |         ^
sh-5.1$
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-25 22:33:59 | 显示全部楼层
本帖最后由 zhangjinxuan 于 2022-11-26 09:23 编辑

你要记住,指针和数组不是同一东西,只是很像罢了

其实任何全局未初始化的全部都是 0,就是不同的类型,不同的表现方式罢了

例如,int, float, double, long 等数字变量没什么好说的,就是 0

而字符串(字符数组)所有元素都是 0,也就是 '\0'

不过指针就不一样了,他初始化都是NULL,为什么呢?我们来看看 NULL 的定义:
#define NULL ((void*)0)
很明显, NULL 就是把 0 转换为了指针,就是不同的类型,不同的表现方式罢了

但,不要想着写 (int*)3 了,只有 0 才可以转换为指针类型,就表示 0x0 这一个空地址,因为空地址是一个系统不常用的地址,所以用来定义 NULL
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-25 22:37:55 | 显示全部楼层
未初始化的会自动初始化为'\0'

行了,这个教材可以不用看了,未定义的行为,意思是让编译器决定怎么整,编译器不初始化成0不行吗?
标准让编译器来处理未定义行为,编译器想做什么就做什么
遇到了未定义行为可以把内存地址0x1024中的值改写成512吗?可以,这没问题
遇到了未定义行为可以把内存地址0~0xffffffff中的值改写成0x1024吗?可以,这没问题
遇到了未定义行为可以让cpu直接瘫痪吗?可以,这没问题
遇到了未定义行为可以发射核弹吗?可以,这没问题,前提是你要安装了能发射核弹的硬件系统
知道了吗?未定义行为就是编译器可以想怎么做就怎么做
讨论这个没有意义,这你得问编译器的设计者,看看他有没有发射核弹的硬件系统
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-25 22:40:57 | 显示全部楼层
        if (imfor.name == NULL)
第2个代码,name是一个数组,你拿他和NULL比较?
这个数组的名字可以是NULL吗?
你哪里见过这样的代码?
sh-5.1$ cat main.c
#include <stdio.h>

int main(void) {
    int array[10] = {0};
    if(array == NULL) printf("\n");
    return 0;
}
sh-5.1$ gcc -g -Wall -o main main.c
main.c: In function ‘main’:
main.c:5:14: warning: the comparison will always evaluate as ‘false’ for the address of ‘array’ will never be NULL [-Waddress]
    5 |     if(array == NULL) printf("\n");
      |              ^~
main.c:4:9: note: ‘array’ declared here
    4 |     int array[10] = {0};
      |         ^~~~~
sh-5.1$
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-25 22:42:56 | 显示全部楼层
the comparison will always evaluate as ‘false’ for the address of ‘array’ will never be NULL
比较将始终评估为“false”,因为“数组”的地址永远不会为空
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-25 22:46:56 | 显示全部楼层
结构体中其他类型的变量又会初始化成什么呢
也许不初始化,直接格式化你的硬盘,有什么问题吗?反正未定义的行为,允许编译器想做什么就做什么
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-25 22:52:40 | 显示全部楼层
zhangjinxuan 发表于 2022-11-25 22:33
你要记住,指针和数组不是同一东西,只是很像罢了

其实任何全局(或结构体)未初始化的全部都是 0,就是 ...

其实任何全局(或结构体)
这里的 ‘或’ 是什么意思?
意思是局部变量也默认初始化成0 ?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-26 00:13:27 From FishC Mobile | 显示全部楼层
弱弱的问一下,全局变量或指针自带初始化默认值吗?我咋没印象⊙﹏⊙∥,哎躺床上手机看,不然实机自己验证一下(ー_ー)!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-26 09:22:55 | 显示全部楼层
人造人 发表于 2022-11-25 22:52
其实任何全局(或结构体)
这里的 ‘或’ 是什么意思?
意思是局部变量也默认初始化成0 ?

我好像被误导了,局部结构体似乎也不能初始化为0
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-26 09:47:22 | 显示全部楼层
人造人 发表于 2022-11-25 22:37
行了,这个教材可以不用看了,未定义的行为,意思是让编译器决定怎么整,编译器不初始化成0不行吗?
...

我已经被搞蒙蔽了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-26 09:58:18 | 显示全部楼层
我已退出群聊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-26 10:08:24 | 显示全部楼层
竹逸 发表于 2022-11-26 00:13
弱弱的问一下,全局变量或指针自带初始化默认值吗?我咋没印象⊙﹏⊙∥,哎躺床上手机看,不然实机自己验证 ...

只要是全局的,不管什么类型,默认值都是0
还有static变量(局部的,全局的都行),不管什么类型,默认值都是0

评分

参与人数 1荣誉 +5 鱼币 +5 贡献 +3 收起 理由
竹逸 + 5 + 5 + 3 鱼C有你更精彩^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-26 11:12:29 From FishC Mobile | 显示全部楼层
人造人 发表于 2022-11-26 10:08
只要是全局的,不管什么类型,默认值都是0
还有static变量(局部的,全局的都行),不管什么类型,默认 ...

我看了自己的笔记,确实没发现说全局自带默认值的,怪不得我没印象(ー_ー)!!

但总结里有一条静态局部变量不赋初值时默认为0(字符型默认是空字符\0)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2022-11-26 18:59:46 | 显示全部楼层
zhangjinxuan 发表于 2022-11-25 22:33
你要记住,指针和数组不是同一东西,只是很像罢了

其实任何全局未初始化的全部都是 0,就是不同的类型, ...

涨知识了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2022-11-26 19:11:25 | 显示全部楼层
人造人 发表于 2022-11-25 22:40
第2个代码,name是一个数组,你拿他和NULL比较?
这个数组的名字可以是NULL吗?
你哪里见过这样的代码 ...

我把指针和数组给搅一起了,以前光想着他们的相似处,完全没注意他们的区别
而且我把NULL是空指针也给忘了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2022-11-26 19:12:47 | 显示全部楼层
人造人 发表于 2022-11-26 10:08
只要是全局的,不管什么类型,默认值都是0
还有static变量(局部的,全局的都行),不管什么类型,默认 ...

编译器不初始化变量,那这个默认值是什么时候赋的呀
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-11-26 19:43:25 | 显示全部楼层
孤不冷cing 发表于 2022-11-26 19:12
编译器不初始化变量,那这个默认值是什么时候赋的呀

操作系统在加载你的程序的时候也许做一次初始化,应该是初始化成0,但是执行到你的main函数以后,堆栈中的数据已经很有可能不是0了,是什么?不知道
这就要看库函数的代码怎么使用的堆栈,当然不止库函数的代码,还有操作系统的代码,所以根本没办法预测这些值是什么

简单来说就是堆栈里面的是一些随机值,编译器如果没有初始化变量的话,那就使用这些随机值

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-26 10:22

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表