V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
thomaswang
V2EX  ›  问与答

c 语言变量默认值问题

  •  
  •   thomaswang · 2018-02-23 23:01:09 +08:00 · 2423 次点击
    这是一个创建于 2225 天前的主题,其中的信息可能已经有所发展或是发生改变。

    声明的 int 类型为什么默认值是 0,结构体 tom.age 默认值是一个随机值呢? tom.name (UU\000\000\300EUUUU)这个默认值是什么啊?

    代码 gdb

    22 条回复    2018-02-26 23:24:31 +08:00
    wevsty
        1
    wevsty  
       2018-02-23 23:14:53 +08:00   ❤️ 1
    未显式初始化的变量其值是多少是一种未定义的行为。
    未定义行为的结果取决于编译器怎么去处理。
    kokutou
        2
    kokutou  
       2018-02-23 23:27:31 +08:00 via Android
    为什么不初始化!!!
    lion9527
        3
    lion9527  
       2018-02-23 23:34:44 +08:00
    局部 int 变量未初始化时默认为随机值。
    全局 int 变量未初始化时默认为 0。
    msg7086
        4
    msg7086  
       2018-02-23 23:44:25 +08:00   ❤️ 2
    随机到了 0 而已,一样是随机的。谁告诉你局部变量有默认值的?
    pkookp8
        5
    pkookp8  
       2018-02-24 01:10:30 +08:00 via Android
    局部变量的值,gcc 的话是在栈上的,不初始化时的值取决于这块内存正好是什么值
    举个例子
    func1()
    {
    int a=123456;
    printf a
    }
    fun2()
    {
    int a;
    printf a
    }
    main()
    {
    func1();
    func2();//这样应该是会打出 123456 的
    }
    一般来说我们会默认它为随机值
    忘了什么编译器好像会自动初始化成一个特定值(微软带的那个?)
    aheadlead
        6
    aheadlead  
       2018-02-24 01:30:06 +08:00
    @pkookp8 一语中的:“局部变量的值,gcc 的话是在栈上的,不初始化时的值取决于这块内存正好是什么值”

    纠正楼上和楼主一个细节:
    你们看到的那都不是随机值,应该叫做不确定的值比较合适。
    am241
        7
    am241  
       2018-02-24 02:10:44 +08:00 via Android
    @pkookp8 烫烫烫烫 cc=int 3
    thomaswang
        8
    thomaswang  
    OP
       2018-02-24 07:55:51 +08:00
    @wevsty 编译的时候每个变量的逻辑地址已经定了,运行的时候,对应的物理地址不定,所以这个值不确定,而且每次的值都不一样?
    thomaswang
        9
    thomaswang  
    OP
       2018-02-24 07:56:55 +08:00
    @kokutou 因为我发现不初始化那个 int id,它居然每次都是 0,我想知道为什么
    thomaswang
        10
    thomaswang  
    OP
       2018-02-24 07:58:13 +08:00
    @msg7086 哈哈,为什么每次都是 0 呢,这个叫什么随机
    thomaswang
        11
    thomaswang  
    OP
       2018-02-24 08:01:04 +08:00
    @aheadlead 多谢纠正,你能解释一下,为什么每次执行结果中,id 都是 0 吗
    wevsty
        12
    wevsty  
       2018-02-24 08:41:55 +08:00
    @thomaswang

    局部变量的声明只确定了使用的内存空间的地址,具体这个地址上的值是什么是不确定的。
    不确定的原因多半是编译器的行为决定的。
    比如:MSVC 在编译 debug 版本时对局部未初始化的 int 变量就会统一的设定为 0xcccccccc
    这里说的随机实际上是,这个值不能确定的意思,并不代表会每次改变。
    最后,切莫太纠结这种未定义的行为,依赖于未定义行为的代码是不具备任何可移植性的,因为它很有可能只能工作在某个编译器的特定版本上。
    harry890829
        13
    harry890829  
       2018-02-24 08:43:27 +08:00
    有的编译器会对未显示初始化的变量进行初始化,有的不会,我印象中 gcc 这种情况下 id 一直会是 0,但是 vc++的话,就不会了。以前吃过亏,声明了一个指针,并没有初始化为 null,然后去判空处理,结果永远是非空,很蛋疼,记住要初始化
    msg7086
        14
    msg7086  
       2018-02-24 09:02:36 +08:00
    @thomaswang
    随机值不是说每次都会生成不同的值,而是内存里正好是什么,就是什么。要是正好是 0,那就一直是 0,但是也可能是别的什么东西。比如以下代码:

    #include <stdio.h>
    int main() {
    int id01, id02, id03, id04, id05, id06, id07, id08, id09, id10, id11, id12, id13, id14, id15, id16, id17, id18, id19, id20, id21, id22, id23, id24, id25, id26, id27, id28, id29, id30;
    printf("id01..10 = %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X\n", id01, id02, id03, id04, id05, id06, id07, id08, id09, id10);
    printf("id11..20 = %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X\n", id11, id12, id13, id14, id15, id16, id17, id18, id19, id20);
    printf("id21..30 = %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X\n", id21, id22, id23, id24, id25, id26, id27, id28, id29, id30);
    return 0;
    }

    ~# ./test
    id01..10 = 00000000 00000000 00007FFC 23F86F40 0000560F 992EE580 0000560F 992EE790 00000000 00000000
    id11..20 = 00000000 00000000 0000560F 992EE7DD 00000000 00000001 00007FCE FAA51FCA 00007FFC 23F86E3E
    id21..30 = 00007FFC 23F86E3F 00000000 000000C2 00000000 00000000 00000000 00000000 00000000 00000000
    ~# ./test
    id01..10 = 00000000 00000000 00007FFD A71865E0 00005635 4A21F580 00005635 4A21F790 00000000 00000000
    id11..20 = 00000000 00000000 00005635 4A21F7DD 00000000 00000001 00007F38 76647FCA 00007FFD A71864DE
    id21..30 = 00007FFD A71864DF 00000000 000000C2 00000000 00000000 00000000 00000000 00000000 00000000
    ~# ./test
    id01..10 = 00000000 00000000 00007FFD 5A537250 0000564B D6EC8580 0000564B D6EC8790 00000000 00000000
    id11..20 = 00000000 00000000 0000564B D6EC87DD 00000000 00000001 00007EFD 9C7E5FCA 00007FFD 5A53714E
    id21..30 = 00007FFD 5A53714F 00000000 000000C2 00000000 00000000 00000000 00000000 00000000 00000000
    ~#
    newtype0092
        15
    newtype0092  
       2018-02-24 10:17:20 +08:00
    在看谭老的书?
    linux40
        16
    linux40  
       2018-02-24 11:04:31 +08:00 via Android
    @lion9527 是看的生命周期,static 和 thread_local 是 0,其它是未定义。
    qq910438219
        17
    qq910438219  
       2018-02-24 11:16:18 +08:00
    随手初始化 习惯
    thomaswang
        18
    thomaswang  
    OP
       2018-02-24 13:29:19 +08:00
    @newtype0092 谭永强? 不知道你说的是哪本,有说上面这个问题吗
    newtype0092
        19
    newtype0092  
       2018-02-24 13:44:32 +08:00
    @thomaswang 谭浩强啊,大学教材,重点讲解各种编译器未定义行为的问题~
    thomaswang
        20
    thomaswang  
    OP
       2018-02-24 13:52:54 +08:00
    @newtype0092 额,我没上过大学
    newtype0092
        21
    newtype0092  
       2018-02-24 14:28:12 +08:00
    @thomaswang 好吧,没关系这是个梗,大学学他教材里就老讲这种茴字有几种写法的问题。。。
    这种东西了解下原理挺有用的,就像上面说的那些,哪些变量分配在堆上哪些在栈上,这些都应该清楚,但去研究像某些默认值这种本来就没有定义的行为,甚至在实际写代码时候使用这些特性绝对是犯蠢。
    就像你开车会漂移,在赛道上漂叫秀,在马路上飘叫作死。
    Arnie97
        22
    Arnie97  
       2018-02-26 23:24:31 +08:00 via Android
    烫烫烫烫烫烫烫烫屯屯屯屯屯屯屯屯
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1006 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 19:49 · PVG 03:49 · LAX 12:49 · JFK 15:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.