【问题标题】:Partially initializing a C struct部分初始化 C 结构
【发布时间】:2016-09-29 14:51:12
【问题描述】:

link 声明“当自动数组或结构具有部分初始化器时,其余部分被初始化为 0”。我决定尝试阅读并编写以下代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
    //int arr[3] = {2};  // line no. 7

    struct s {
        int si;
        int sj;
    };

    struct s myStruct;
    myStruct.si = 9;
    printf("%d\n", myStruct.sj);
}

我不明白为什么当我注释掉line no. 7 时会打印4096(我认为这是一些“垃圾”值),而当我取消注释line no. 7 时会得到0。我认为arr 声明与main() 的激活记录(或者更确切地说myStruct)无关,它应该看起来像(假设我们有line no. 7 未注释):

---------------
|  Saved PC   |
---------------
|  arr[2]     |
---------------
|  arr[1]     |
---------------
|  arr[0]     |
---------------
|  si         |
---------------
|  sj         |
---------------

有人可以解释一下我在这里缺少什么吗?

【问题讨论】:

标签: c struct initialization variable-assignment


【解决方案1】:

当你这样做时:

struct s myStruct;
myStruct.si = 9;

你没有初始化myStruct。你声明它没有初始化器,然后运行一个语句来设置一个字段。

由于变量未初始化,其内容未定义,读取为undefined behavior。这意味着看似无关的更改可以修改此行为。在您的示例中,添加一个额外的变量 happened 导致 myStruct.sj 为 0,但不能保证会出现这种情况。

初始化一个变量,你必须在它被定义的时候给它一个值:

struct s myStuct = { 9 };

执行此操作后,您将看到 myStruct.sj 的内容设置为 0。这是根据 the C standard 的第 6.7.8 节保证的(针对这种情况突出显示):

10 如果具有自动存储持续时间的对象不是 显式初始化,它的值是不确定的。 如果一个对象 具有静态存储持续时间的未初始化 明确,然后:

——如果它有指针类型,它被初始化为空 指针;

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

如果是聚合,每个成员都被初始化 (递归地)根据这些规则;

——如果是联合,则第一个 根据这些规则(递归地)初始化命名成员。

...

21 如果大括号括起来的列表中的初始值设定项比那里少 是聚合的元素或成员,或 用于初始化已知大小的数组的字符串文字 是数组中的元素,聚合的其余部分 应隐式初始化,与具有静态的对象相同 存储期限。

【讨论】:

  • declare it without an initializer 是一个很好的表达方式。作为旁注,还没有答案解释I get 0 when I uncomment line no. 7
  • 编译器选项可以设置为将所有内存初始化为零,某些操作系统可能会这样做,但myStruct.sj 可以是@dbush 指出的任何内容。如果myStruct.sj 是一个指针,那么未初始化的值可能会引起各种麻烦,我遇到过这种情况。
  • @MichaelShopsin :如果没有设置编译器选项,您能否举一个 some operating systems that do so 的示例。我相信Linux和Windows都不会这样做..
  • 关于“当我取消注释第 7 行时我得到 0”:正如 dbush 所指出的(“看似不相关的变化......添加了一个额外的变量导致 myStruct.sj 为 0"),根据定义,它是未定义的,在 合理的实践中,它是任何碰巧留在那段内存中的东西。如果您要改变arr[3] 定义的大小(从而改变内存映射中sisj 的内存深度),您可能得到一系列值.
  • @Spotlight 这就是 OP 最初拥有的。他设置了si,并认为这是一个初始化,预计sj 为0。
【解决方案2】:

对于其他人已经给出的出色答案,这基本上是一个或多或少完整的示例。

#include<stdio.h>

struct{
  int a;
  int b;
}obj1={.a=0}; //Partial initialization

typedef struct struct_B{
  int a;
  int b;
}struct_B;

int main(void)
{
  printf("obj1.b : %d\n",obj1.b);
  struct_B obj2={.b=1,.a=0,0}; // b's first value is overridden here as 0 immediately follows a
  printf("obj2.b : %d\n",obj2.b);
  struct_B obj3={0}; //Partial initialization, here the '0' value is meant for a as it comes first in the declaration
  printf("obj3.b : %d\n",obj3.b);
  struct_B obj4={.a=0}; //Partial initialization
  printf("obj4.b : %d\n",obj4.b);
  return 0;
}

输出:

obj1.b : 0
obj2.b : 0
obj3.b : 0
obj4.b : 0

【讨论】:

    【解决方案3】:

    在你的情况下,

     myStruct.si = 9;
    

    assignment 声明,不是 initialization。在这种情况下,结构变量(和相应的变量)未初始化。因此,您最终会读取未初始化变量 sj 的值,这会导致 undefined behavior

    你可以试试

    struct s myStruct = {9};
    

    查看隐式初始化的实际效果。

    【讨论】:

      【解决方案4】:

      这不是初始化程序——你的结构没有初始化,然后你只分配sisj 仍未初始化。

      这本书指的是这种代码:

      struct s myStruct = {9};
      

      ...sj 保证为 0。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-02
        • 2012-07-16
        • 1970-01-01
        • 1970-01-01
        • 2016-12-11
        相关资源
        最近更新 更多