根据C99 standard6.5.2.5.9,代码:

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

初始化p以指向由两个int组成的数组的第一个元素,
第一个值为2,第二个值为4。中的表达式
此复合文字必须为常量。未命名对象
具有静态存储持续时间。
但是当我们这样做的时候会发生什么呢:
int* arr[100];
for (int a=0; a<100; a++) {
  arr[a] = (int []){2, 4};
}

是在循环的每次迭代中创建一个新的unnamed object还是在每次迭代中使用同一个项目?
如果我们这样做,结果会不同吗:
int* ptr = NULL;
for (int a=0; a<100; a++) {
  ptr = (int []){2, 4};
}

两个可能的选项是:每次循环迭代都创建一个新对象,或者每次循环迭代都使用同一个对象。
我感兴趣的是,这种情况下的行为是否可以从标准中所写的内容中扣除,还是由编译器来决定。
我已经在GCC4.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");
}

结果是:
0x7fff4c010a0 0x7fff4c010a0 0x7fff4c010a0 0x7fff4c010a0
0x7fff4c010a0 0x7fff4c010a0 0x7fff4c010a0 0x7fff4c010a0
0x7fff4c010a0 0x7fff4c010a0
我写了一些代码来检查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指出,如果复合文字出现在功能体内,
…它具有与封闭关联的自动存储持续时间
封锁。
所以,没有歧义。在本例中,复合文字具有自动存储持续时间,该持续时间持续到包含它的循环块的末尾-概念上,为循环的每次迭代创建和销毁新的复合文字,但由于这些文字的生命周期不重叠,实现可能会重新使用相同的空间。你写的和这没什么不同:

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/

10-11 16:41