【问题标题】:Bulk initialize the char array by "\0" instead of memset()通过“\0”而不是 memset() 批量初始化 char 数组
【发布时间】:2019-10-19 02:24:39
【问题描述】:

通常由memset 初始化的字符数组批量。

我在我的项目代码中发现了由"\0" 初始化的char 数组。我也编译并检查过,它工作正常。

我的问题是这是批量初始化 char 数组的正确方法吗?

例如:

char a[20]="\0";
printf("%s", a);

【问题讨论】:

  • 你说的bulk初始化是什么意思?
  • 它与char a[20]={0, 0} 相同,因为port70.net/~nsz/c/c11/n1570.html#6.7.9p21 起作用
  • 也和char a[20] = "";一样 字符串定义不需要显式的终止符。
  • 批量初始化意味着将数组的所有元素初始化为特定值@EugeneSh。

标签: c++ c arrays char


【解决方案1】:

是的,这是正确的方法之一。

引用C11,第 6.7.9 章

如果大括号括起来的列表中的初始值设定项少于元素或成员的数量 用于初始化已知数组的字符串文字中的聚合或更少字符 大小超过数组中的元素,聚合的其余部分应为 隐式初始化与具有静态存储持续时间的对象相同。

关于static存储变量的初始化,

如果具有静态或线程存储持续时间的对象未初始化 明确地,那么:

——如果是指针类型,则初始化为空指针;

——如果是算术类型,则初始化为(正或无符号)零;

——如果它是一个聚合,每个成员都根据这些规则被初始化(递归), 并且任何填充都被初始化为零位;

——如果它是一个联合,第一个命名的成员根据这些被初始化(递归) 规则,并且任何填充都被初始化为零位;

引用C++17,第 11.6.2 章

如果初始化器的数量少于数组元素的数量,则每个未显式初始化的元素都应为 零初始化。


所以,在你的情况下,

char a[20]="\0";

尝试将a[0] 初始化为'\0',将a[1] 初始化为'\0'(用于空终止符),其余为0。 FWIW,'\0' 的十进制值为0,因此在这种情况下,数组中的所有元素都将有一个值0

一些类似的初始化语句是

char a[20] = "";
char a[20] = {0};
char a[20] = {'\0'};

对于C++,建议in the other answer,包括之前的所有语法,

char a[20] = {};

也可以。

【讨论】:

  • 可能是因为所提供的代码非常接近 C++。 (考虑编辑掉cout?)
  • @Bathsheba 我实际上链接到您对 CPP 部分的回答,但感谢您的编辑。
  • @zwol 同意,添加。
  • 历史注释:对整个数组进行零初始化的字符串字面量是在 C99 中添加的;旧的 C89 编译器可能不会这样做
【解决方案2】:

它以一种奇怪的方式几乎是偶然的,在我看来,它是一种混淆练习。一个解释:

在 C++ 中,"\0" 是一个 const char[2] 文字,其值为 '\0'(值为 0 的八进制常数)后跟一个 NUL 终止符,即两个 0 值。在 C 中,它是一个具有相同值的 char[2] 常量。

初始化a 也会导致a 的其他元素也初始化为0(根据C 和C++ 标准,其他元素根据static 存储持续时间进行初始化)。

在 C++ 中写 char a[20] = {} 就足够了,在 C 中你至少需要 char a[20] = {0}

【讨论】:

    【解决方案3】:

    是的。它之所以有效,是因为使用初始化程序来初始化一些子对象 (在这里你明确地初始化前两个)导致其余部分被初始化为零(更精确地初始化就像它们是静态的一样 - 即指针被设置为空指针常量,即使它不是所有位都为零给定的架构)。

    更通用的版本是:

    any_composite_type x={0};
    

    编译器可能并且仍然通过调用 memset 来实现此类初始化

    例子:

    struct foo{
        char big[1000];
    };
    void take_foo(struct foo*);
    int main()
    {
        struct foo obj ={0};
        take_foo(&obj);
    }
    

    compiled with clang for x86-64:

    main:                                   # @main
            push    rbx
            sub     rsp, 1008
            lea     rbx, [rsp + 8]
            mov     edx, 1000
            mov     rdi, rbx
            xor     esi, esi
            call    memset
            mov     rdi, rbx
            call    take_foo
            xor     eax, eax
            add     rsp, 1008
            pop     rbx
            ret
    

    (以类似的方式,他们可能并且确实将对memset的显式调用替换为 如果他们看到 memsetted 的对象很小,则内联程序集。)

    【讨论】:

      猜你喜欢
      • 2014-08-04
      • 2019-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-25
      • 2010-11-05
      • 1970-01-01
      • 2017-06-27
      相关资源
      最近更新 更多