c - 每次将复合文字分配给循环中的指针时是否都会创建一个新对象?

标签 c c99 compound-literals

根据 C99 standard 6.5.2.5 .9 代码:

int *p = (int []){2, 4};

initializes p to point to the first element of an array of two ints, the first having the value two and the second, four. The expressions in this compound literal are required to be constant. The unnamed object has static storage duration.

但是当我们这样做时会发生什么:

int* arr[100];
for (int a=0; a<100; a++) {
  arr[a] = (int []){2, 4};
}

是在循环的每次迭代中创建一个新的未命名对象,还是每次迭代都使用同一个对象?

如果我们这样做,结果会不会不同:

int* ptr = NULL;
for (int a=0; a<100; a++) {
  ptr = (int []){2, 4};
}

两种可能的选择是:每次循环迭代时创建一个新对象,或者每次循环迭代使用相同的对象。

我感兴趣的是这种情况下的行为是否可以以某种方式从标准中的内容中推导出来,还是由编译器决定。

我已经用这段代码在 gcc 4.1.2 下测试了它:

int main(void) {
  int* arr[100];
  for (int a=0; a<10; a++) {
      arr[a] = (int []){2, 4};
      printf("%p ", arr[a]);
  }
  printf("\n");
}

结果是:

0x7fff4c0010a0 0x7fff4c0010a0 0x7fff4c0010a0 0x7fff4c0010a0 0x7fff4c0010a0 0x7fff4c0010a0 0x7fff4c0010a0 0x7fff4c0010a0 0x7fff4c0010a0 0x7fff4c0010a0

我写了一些代码来检查caf的答案:

void fillArr(int* arr[]) {
  for (int a=0; a<4; a++) {
    arr[a] = (int []){a, a};
    printf("%p %d |  ", arr[a], arr[a][0]);
  }
}

void fillArr2(int* arr[]) {
  for (int a=0; a<4; a++) {
    int temp[] = { a, a };
    arr[a] = temp;
    printf("%p %d |  ", arr[a], arr[a][0]);
  }
}


int main(void) {
  int* arr[4];
  printf("\nfillarr1 function scope\n");
  fillArr(arr);


  printf("\nfillArr main scope\n");
  for (int a=0; a<4; a++) {
    printf("%p %d | ", arr[a], arr[a][0]);
  }

  printf("\nfillArr2 function scope\n");
  fillArr2(arr);

  printf("\nfillArr2 main scope\n");
  for (int a=0; a<4; a++) {
    printf("%p %d | ", arr[a], arr[a][0]);
  }

  printf("\n");
}

结果是(用 valgrind 调用它来检测内存错误):

==19110== Memcheck, a memory error detector
==19110== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==19110== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==19110== Command: ./a.out
==19110==

fillarr1 function scope
0x7ff000830 0 |  0x7ff000830 1 |  0x7ff000830 2 |  0x7ff000830 3 |
fillArr main scope
==19110== Use of uninitialised value of size 8
==19110==    at 0x3E33A41B1D: _itoa_word (in /lib64/libc-2.5.so)
==19110==    by 0x3E33A44F44: vfprintf (in /lib64/libc-2.5.so)
==19110==    by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110==    by 0x400664: main (literalstest.c:26)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110==    at 0x3E33A41B27: _itoa_word (in /lib64/libc-2.5.so)
==19110==    by 0x3E33A44F44: vfprintf (in /lib64/libc-2.5.so)
==19110==    by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110==    by 0x400664: main (literalstest.c:26)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110==    at 0x3E33A44FBE: vfprintf (in /lib64/libc-2.5.so)
==19110==    by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110==    by 0x400664: main (literalstest.c:26)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110==    at 0x3E33A4574A: vfprintf (in /lib64/libc-2.5.so)
==19110==    by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110==    by 0x400664: main (literalstest.c:26)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110==    at 0x3E33A43C49: vfprintf (in /lib64/libc-2.5.so)
==19110==    by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110==    by 0x400664: main (literalstest.c:26)
==19110==
0x7ff000830 864144320 | 0x7ff000830 864144320 | 0x7ff000830 864144320 | 0x7ff000830 864144320 |
fillArr2 function scope
0x7ff000830 0 |  0x7ff000830 1 |  0x7ff000830 2 |  0x7ff000830 3 |
fillArr2 main scope
==19110== Use of uninitialised value of size 8
==19110==    at 0x3E33A41B1D: _itoa_word (in /lib64/libc-2.5.so)
==19110==    by 0x3E33A44F44: vfprintf (in /lib64/libc-2.5.so)
==19110==    by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110==    by 0x4006B9: main (literalstest.c:34)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110==    at 0x3E33A41B27: _itoa_word (in /lib64/libc-2.5.so)
==19110==    by 0x3E33A44F44: vfprintf (in /lib64/libc-2.5.so)
==19110==    by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110==    by 0x4006B9: main (literalstest.c:34)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110==    at 0x3E33A44FBE: vfprintf (in /lib64/libc-2.5.so)
==19110==    by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110==    by 0x4006B9: main (literalstest.c:34)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110==    at 0x3E33A4574A: vfprintf (in /lib64/libc-2.5.so)
==19110==    by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110==    by 0x4006B9: main (literalstest.c:34)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110==    at 0x3E33A43C49: vfprintf (in /lib64/libc-2.5.so)
==19110==    by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110==    by 0x4006B9: main (literalstest.c:34)
==19110==
0x7ff000830 864144320 | 0x7ff000830 864144320 | 0x7ff000830 864144320 | 0x7ff000830 864144320 |
==19110==
==19110== HEAP SUMMARY:
==19110==     in use at exit: 0 bytes in 0 blocks
==19110==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==19110==

因此文字仅在声明它们的函数内部可用,离开函数后超出范围,之后访问它们是未定义的行为。

最佳答案

您误读了标准。您给出的示例以“文件范围定义...”开头,但您的代码不能出现在文件范围内。

§6.5.2.5 p6 说如果复合文字出现在函数体内,

...it has automatic storage duration associated with the enclosing block.

所以,没有歧义。这种情况下的复合文字具有自动存储持续时间,持续到包含它的循环 block 结束 - 从概念上讲,为循环的每次迭代创建和销毁一个新的复合文字,但由于这些文字的生命周期不重叠,实现可能会重复使用相同的空间。你写的和这个没有什么不同:

int *arr[100];
for (int a=0; a<100; a++) {
  int temp[] = { 2, 4 };
  arr[a] = temp;
}

...只是在复合文字的情况下,数组是未命名的。生命周期是一样的。

关于c - 每次将复合文字分配给循环中的指针时是否都会创建一个新对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17037230/

相关文章:

c - 如何格式化C中的文本输出

带循环 inC 的字符输入?

c - 如何正确地为数组(结构类型)元素赋值?

c - 从文件加载 RSA key

c - 为什么 *ptr.member 错误而 (*ptr).member 正确?

在 for 循环中递减的更清洁的解决方案

c - bss 和数据段中的整数变量大小

c - Visual Studio 2008 限制为 ANSI C

c - 复合文字的生命周期

c - 为什么 Clang 会为本地复合文字提示 "initializer element is not a compile-time constant"?