网站LOGO
一路の数字花园 | Luyi's Blog
页面加载中
9月4日
网站LOGO 一路の数字花园 | Luyi's Blog
༺ζ❀梦里花落知多少꧔ꦿ༊
菜单
  • 用户的头像
    首次访问
    上次留言
    累计留言
    我的等级
    我的角色
    打赏二维码
    打赏博主
    C变量真的都可以使用{0}来初始化吗?
    点击复制本页信息
    微信扫一扫
    文章二维码
    文章图片 文章标题
    创建时间
  • 一 言
    确认删除此评论么? 确认
  • 本弹窗介绍内容来自,本网站不对其中内容负责。
    • 复制图片
    • 复制图片地址
    • 百度识图
    按住ctrl可打开默认菜单

    C变量真的都可以使用{0}来初始化吗?

    一路 · 原创 ·
    C/C++语言 · C/C++C基础C陷阱
    共 2050 字 · 约 6 分钟 · 21

    楔子

    不知道大家编码时有没有遇到过这样的情况:在一个函数中定义了一个局部的结构体变量,这个结构体里包含了很多不同类型的成员,导致在初始化该结构体成员时,每个成员都要赋对应的初值。就像下面这样:

    c 代码:
       struct {
           char a;        // 字符
           int b;            // 整型 
           int* c;        // 指针
           int d[3];      // 数组
       } str_value = {.a = '\0', .b = 0, .c = NULL, .d = {0,0,0}};

    “有考虑过直接使用 ={0} 来对结构体变量赋初始值,但又害怕产生不可预料的行为。”
    有上面 👆 这样的想法是因为 C 语言中的整型变量使用 0 来初始化是显而易见的,就是整数 0,但字符、指针和数组这些看起来与整型数不那么匹配的变量类型,使用 0 真的可行吗?

    我想这是很多初学者甚至工作多年的老鸟都疑惑的问题。那么要解开这个困惑,我们就先从编译器的行为开始分析。

    先说结论,是完全可以使用 0 值来对不同类型成员进行默认值初始化的。


    编译器行为

    还是以上面的 str_value 变量为例,我们在定义这个变量时会有两种情况,可能定义为静态变量(全局变量),或是定义为非静态变量(局部变量) 。当定义为静态变量时,往往不需要考虑初始化的问题

    尽管我们知道变量是在定义时就应初始化,否则其值会是内存中的任意“垃圾值”。但我们往往相信编译器与我们多年的“共事”已经心生情愫,绝不会坑我们,它一定会引导所定义的变量自动赋予正确的初始值 😶。

    事实也的确如此~ 那编译器在赋值时到底赋了什么呢?
    答:当静态变量定义时,编译器会给未显式初始化的成员自动分配 0 值

    其实通过窥探编译器这一行为,基本就认定了开发者在进行初始化时可以使用 ={0} 来操作,这相当于是在模仿编译器的行为。

    不同类型处理 0 值

    到这里,我们仅仅知道用 0 值初始化行为没有错,但我们还不了解为什么可以用 0 来对不同类型的变量进行初始化。这就涉及到每种类型在处理 0 值时的底层逻辑了。

    字符

    字符与整数值的转换需要参考 ASCII 码,其中数值 0 对应的字符是 NUL(空字符)。在 C 语言中,没有专门的“空字符”类型,而是直接用整数值 0 或转义字符 '\0' 来表示。所以 0 等于 '\0',在 C 语言中 '\0' 就是字符类型的默认初始值,因此同样也可以用 0 来表示。

    指针

    通常指针的默认初始值为 NULL(空指针),这个和字符 NUL 很像,但我们不去从这个角度考虑它和 0 值的关系,而是看看 C 语言标准库中是如何定义 NULL 这个宏的。

    以 GCC 为例,在 <stddef.h> 这个标准头文件中,有这么一行代码:#define NULL ((void*)0),它的含义是『定义一个宏 NULL,它代表地址 0x00』,更直白地说,就是如果我强行把电脑内存地址 0x00 处的值改为 n,那么 NULL 解引用后的值就是 n。因此,代码 str_value.c = NULL; 就相当于 str_value.c = ((void*)0);

    在机器中,地址 0x00 是绝对的禁区,操作系统会通过内存管理单元(MMU)硬性保护这片区域,任何程序都无权对其进行读写操作。从操作系统内核的角度看,地址 0x00 的值通常是 0。但这其实也不是 0 值与地址 0x00 混用的根本原因,实际上 C 标准为了类型安全和程序员便利而引入的一条特殊规则:An integer constant expression with the value 0, or such an expression cast to type void*,因此,在使用 0 值对指针赋值时,其实会自动转换为 (void*)0,代码 str_value.c = 0; 等同于 str_value.c = ((void*)0); 等同于 str_value.c = NULL;

    数组

    数组本质上是整型、字符或指针等类型的集合,处理 0 值的原理与单变量处理是没有区别的,只要认真看完上面的内容基本就能理解。

    但需要注意的是,数组和结构体初始化时的 ={0} 操作和赋值时 =0 操作是不同的,在 C 语言中进行 ={0} 初始化是一种聚合赋值的行为,会把所有成员都赋 0

    综上所述,不管是整型 int、字符型 char 还是指针型 int*,都是可以使用 0 值作为默认初始值的。


    变量初始化问题延申

    • 静态变量在未确定初始化值前,推荐不进行手动初始化(可依赖编译器自动零初始化);
    • 非静态局部变量和常量一定要进行显性初始化;
    • 数组和结构体在初始化赋 0 值时可以使用 ={0} 的方式,而非必须 memset 方式,但这个数组必须是大小确定的
    声明:本文由 一路 (博主)原创,依据 CC-BY-NC-SA 4.0 许可协议 授权,转载请注明出处。

    还没有人喜爱这篇文章呢

    我要发表评论 我要发表评论
    博客logo 一路の数字花园 | Luyi's Blog ༺ζ❀梦里花落知多少꧔ꦿ༊ 51统计
    ICP 鄂ICP备2025098605号 尊重原创内容,接纳多元文化,抵制不良信息,共建和谐网络。举报邮箱:luyi.hub@foxmail.com

    💻️ 站长 27分钟前 在线

    🕛

    本站已运行 172 天 9 小时 22 分

    ❤️

    Power by Typecho & MyLife | Dev by Luyi
    一路の数字花园 | Luyi's Blog. © 2025 ~ 2025.
    网站logo

    一路の数字花园 | Luyi's Blog ༺ζ❀梦里花落知多少꧔ꦿ༊