Is a new object created each time a compound literal is assigned to a pointer in a loop?

StackOverflow https://stackoverflow.com/questions/17037230

  •  31-05-2022
  •  | 
  •  

Вопрос

According to C99 standard 6.5.2.5 .9 the code:

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.

But what happens when we do something like this:

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

is a new unnamed object create with each iteration of the loop or is the same oject used for each iteration?

Would the result be different if we did something like this:

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

The two possible options are: a new object is created each time the loop iterates or the same object is used for each loop iteration.

I am interested whether the behavior in this situation can somehow be deducted from what is written in the standard, or is it up to compiler to decide.

I have tested it under gcc 4.1.2 with this code:

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

And the result is:

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

I wrote some code to check caf's answer:

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");
}

And the result is (called it with valgrind to detect memory errors):

==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==

So the literals are available only inside the function they were declared in, go out of scope after leaving the function and after that accessing them is undefined behavior.

Это было полезно?

Решение

You are misreading the standard. The example you gave starts "The file scope definition...", but your code cannot appear at file scope.

§6.5.2.5 p6 says that if a compound literal occurs within a function body,

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

So, there is no ambiguity. The compound literal in this case has automatic storage duration that lasts until the end of the loop block in which it is contained - conceptually a new compound literal is created and destroyed for each iteration of the loop, but since the lifetimes of those literals do not overlap, the implementation may re-use the same space. What you've written is no different to this:

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

...it's just that in the compound literal case, the array is unnamed. The lifetime is the same.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top