Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jquery/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 使用指定的初始值设定项初始化数组时出现奇怪值_C_Arrays_Runtime Error_Designated Initializer_Unspecified Behavior - Fatal编程技术网

C 使用指定的初始值设定项初始化数组时出现奇怪值

C 使用指定的初始值设定项初始化数组时出现奇怪值,c,arrays,runtime-error,designated-initializer,unspecified-behavior,C,Arrays,Runtime Error,Designated Initializer,Unspecified Behavior,当我初始化下面的数组时,除了值[3]之外,所有输出看起来都正常。由于某种原因,values[3]初始化为values[0]+values[5]正在输出一个非常大的数字。我的猜测是,我试图在将值[0]+值[5]正确存储在内存中之前分配它们,但如果有人能解释一下,那就太好了 int main (void) { int values[10] = { [0]=197,[2]=-100,[5]=350, [3]=values[0] + values[5],

当我初始化下面的数组时,除了
值[3]
之外,所有输出看起来都正常。由于某种原因,
values[3]
初始化为
values[0]+values[5]
正在输出一个非常大的数字。我的猜测是,我试图在将
值[0]+值[5]
正确存储在内存中之前分配它们,但如果有人能解释一下,那就太好了

int main (void)
{

    int values[10] = { 
        [0]=197,[2]=-100,[5]=350,
        [3]=values[0] + values[5],
        [9]= values[5]/10
    };

    int index;

    for (index=0; index<10; index++)
        printf("values[%i] = %i\n", index, values[index]);


    return 0;
}
编辑:

该文件规定:

初始化应按初始化器列表顺序进行,每个 为覆盖任何子对象的特定子对象提供的初始值设定项 以前列出的同一子对象的初始值设定项;132)全部 未显式初始化的子对象应初始化 隐式地与具有静态存储持续时间的对象相同

但正如所指出的,评估顺序不必与初始化顺序匹配

这意味着
值[0]+值[5]
可以从以下位置读取垃圾值:

  • 值[0]
  • 值[5]
    (您的情况就是这样)
  • 两者
  • 没有一个

由于C99标准草案第6.7.8节
中未指定初始化列表表达式的求值顺序,您在这里似乎受到未指定行为的影响:

初始化过程中出现任何副作用的顺序 列表表达式未指定。133)

注133说:

特别是,评估顺序不必与顺序相同 子对象初始化的

  int values[10];

  values[2] = -100;
  values[5] = 350;
  values[3] = values[0] + values[5];
  ...
据我所知,支持注释
133
的规范性文本将来自第
6.5节:

除非下文另有规定,[…]评估的顺序 子表达式和副作用发生的顺序都是 未指明

我们可以看到initializer是
6.8
(emphasis mine)中的完整表达式:

完整表达式是不属于另一个表达式的表达式 声明符的表达式或表达式。 以下各项均为完整表达式:初始值设定项;[……]

回顾我的一篇文章,它涵盖了初始值设定项中的一个序列点,并将完整表达式放在了与我最初得出结论不同的位置,然后我两次意识到
6.7.8
中包含初始值设定项的语法:

我最初没有注意到这一点,并认为关于完整表达式的语句适用于上述语法中的顶部元素

我相信,像C++一样,完整表达式应用到初始化列表中的每个初始化器,这使得我以前的分析不正确。 证实了我的怀疑,事实确实如此,它包含以下示例:

#include <stdio.h>

#define ONE_INIT      '0' + i++ % 3
#define INITIALIZERS      [2] = ONE_INIT, [1] = ONE_INIT, [0] = ONE_INIT

int main()
{
    int i = 0;
    char x[4] = { INITIALIZERS }; // case 1
    puts(x);
    puts((char [4]){ INITIALIZERS }); // case 2
    puts((char [4]){ INITIALIZERS } + i % 2); // case 3
}
或:

这是未定义的行为,因为使用了

在这种特定情况下,最简单的解决方法是手动执行计算:

int values[10] = { 
    [0]=197,[2]=-100,[5]=350,
    [3]= 197 + 350,
    [9]= 350/10
};

还有其他替代方法,例如在初始化之后对元素
3
9
进行赋值。

这与指定的初始值设定者本身无关。这与您尝试以下操作时遇到的错误相同:

int array[10] = {5, array[0]};
  int values[10];

  values[2] = -100;
  values[5] = 350;
  values[3] = values[0] + values[5];
  ...
初始化列表表达式的执行顺序只是未指定的行为。这意味着它是特定于编译器的、未记录的,永远不应依赖:

C116.7.9/23

初始化列表表达式的计算如下所示 相互之间不确定的顺序,因此 任何副作用发生的顺序尚未确定

由于您使用数组项初始化其他数组成员,这意味着您必须将代码更改为运行时分配,而不是初始化

  int values[10];

  values[2] = -100;
  values[5] = 350;
  values[3] = values[0] + values[5];
  ...

作为一个副作用,您的程序现在也将更具可读性。

这是我第一次看到这样初始化的东西,但我认为您看到的行为与访问尚未初始化的数组片段有关。所以我在32位Ubuntu 12.04系统上使用GCC4.6.3构建了它。在我的环境中,我得到的结果与你不同

gcc file.c -o file

./file
values[0] = 197
values[1] = 0
values[2] = -100
values[3] = 197
values[4] = 0
values[5] = 350
values[6] = 0
values[7] = 0
values[8] = 0
values[9] = 35


objdump -d file > file.asm

cat file.asm     (relevant portion posted below)

080483e4 <main>:
 80483e4:   55                      push   %ebp
 80483e5:   89 e5                   mov    %esp,%ebp
 80483e7:   57                      push   %edi
 80483e8:   53                      push   %ebx
 80483e9:   83 e4 f0                and    $0xfffffff0,%esp
 80483ec:   83 ec 40                sub    $0x40,%esp
 80483ef:   8d 5c 24 14             lea    0x14(%esp),%ebx
 80483f3:   b8 00 00 00 00          mov    $0x0,%eax
 80483f8:   ba 0a 00 00 00          mov    $0xa,%edx
 80483fd:   89 df                   mov    %ebx,%edi
 80483ff:   89 d1                   mov    %edx,%ecx
 8048401:   f3 ab                   rep stos %eax,%es:(%edi)   <=====
 8048403:   c7 44 24 14 c5 00 00    movl   $0xc5,0x14(%esp)
 804840a:   00 
 804840b:   c7 44 24 1c 9c ff ff    movl   $0xffffff9c,0x1c(%esp)
 8048412:   ff
 8048413:   8b 54 24 14             mov    0x14(%esp),%edx
 8048417:   8b 44 24 28             mov    0x28(%esp),%eax
 804841b:   01 d0                   add    %edx,%eax
 804841d:   89 44 24 20             mov    %eax,0x20(%esp)
 8048421:   c7 44 24 28 5e 01 00    movl   $0x15e,0x28(%esp)
 8048428:   00 
 8048429:   8b 4c 24 28             mov    0x28(%esp),%ecx
 804842d:   ba 67 66 66 66          mov    $0x66666667,%edx
 8048432:   89 c8                   mov    %ecx,%eax
 8048434:   f7 ea                   imul   %edx
 8048436:   c1 fa 02                sar    $0x2,%edx
 8048439:   89 c8                   mov    %ecx,%eax
 804843b:   c1 f8 1f                sar    $0x1f,%eax
gcc文件.c-o文件
/文件
值[0]=197
值[1]=0
值[2]=-100
数值[3]=197
值[4]=0
数值[5]=350
值[6]=0
值[7]=0
值[8]=0
数值[9]=35
objdump-d file>file.asm
cat file.asm(相关部分如下所示)
080483e4:
80483e4:55推送百分比ebp
80483e5:89 e5移动百分比esp,%ebp
80483e7:57推送百分比edi
80483e8:53推送百分比ebx
80483e9:83 e4 f0和$0xfffffff0,%esp
80483ec:83 ec 40子$0x40,%esp
80483ef:8d 5c 24 14 lea 0x14(%esp),%ebx
80483f3:b8 00 mov$0x0,%eax
80483f8:ba 0a 00 mov$0xa,%edx
80483fd:89 df mov%ebx,%edi
80483ff:89 d1 mov%edx,%ecx
8048401:f3 ab rep stos%eax,%es:(%edi)请尝试以下代码:

int values[10];
values[0]=197;
values[2]=-100;
values[5]=350;
values[3]=values[0]+values[5];
values[9]=values[5]/10;

然后像以前一样打印数组。

W-这种疯狂的数组初始化语法是什么?这到底是如何合法和编译的?@tux3:@tux3,这是C99中引入的指定初始化语法。您确定值[0]和[5]在到达[3]时已经有了它们的值吗?我想这是不能保证的。@Mat:“疯狂初始化synatx”和“在C99中”不是相互排斥的条件。如果标准中有某种东西,但它确实很愚蠢,或者比替代品更不清晰,那么为什么要使用它?行为是未指定的,还是未定义的?@Bathsheba未指定。但是仍然不应该被依赖,因为编译器在涉及到未指定的行为时,实际的行为可能会因情况而异,即使顺序是从左到右
  int values[10];

  values[2] = -100;
  values[5] = 350;
  values[3] = values[0] + values[5];
  ...
gcc file.c -o file

./file
values[0] = 197
values[1] = 0
values[2] = -100
values[3] = 197
values[4] = 0
values[5] = 350
values[6] = 0
values[7] = 0
values[8] = 0
values[9] = 35


objdump -d file > file.asm

cat file.asm     (relevant portion posted below)

080483e4 <main>:
 80483e4:   55                      push   %ebp
 80483e5:   89 e5                   mov    %esp,%ebp
 80483e7:   57                      push   %edi
 80483e8:   53                      push   %ebx
 80483e9:   83 e4 f0                and    $0xfffffff0,%esp
 80483ec:   83 ec 40                sub    $0x40,%esp
 80483ef:   8d 5c 24 14             lea    0x14(%esp),%ebx
 80483f3:   b8 00 00 00 00          mov    $0x0,%eax
 80483f8:   ba 0a 00 00 00          mov    $0xa,%edx
 80483fd:   89 df                   mov    %ebx,%edi
 80483ff:   89 d1                   mov    %edx,%ecx
 8048401:   f3 ab                   rep stos %eax,%es:(%edi)   <=====
 8048403:   c7 44 24 14 c5 00 00    movl   $0xc5,0x14(%esp)
 804840a:   00 
 804840b:   c7 44 24 1c 9c ff ff    movl   $0xffffff9c,0x1c(%esp)
 8048412:   ff
 8048413:   8b 54 24 14             mov    0x14(%esp),%edx
 8048417:   8b 44 24 28             mov    0x28(%esp),%eax
 804841b:   01 d0                   add    %edx,%eax
 804841d:   89 44 24 20             mov    %eax,0x20(%esp)
 8048421:   c7 44 24 28 5e 01 00    movl   $0x15e,0x28(%esp)
 8048428:   00 
 8048429:   8b 4c 24 28             mov    0x28(%esp),%ecx
 804842d:   ba 67 66 66 66          mov    $0x66666667,%edx
 8048432:   89 c8                   mov    %ecx,%eax
 8048434:   f7 ea                   imul   %edx
 8048436:   c1 fa 02                sar    $0x2,%edx
 8048439:   89 c8                   mov    %ecx,%eax
 804843b:   c1 f8 1f                sar    $0x1f,%eax
int values[10];
values[0]=197;
values[2]=-100;
values[5]=350;
values[3]=values[0]+values[5];
values[9]=values[5]/10;