programing

C/C++에서 0 사이즈의 어레이를 정의하면 어떻게 됩니까?

shortcode 2022. 7. 10. 21:12
반응형

C/C++에서 0 사이즈의 어레이를 정의하면 어떻게 됩니까?

궁금해서 , 어레이를 이 일어날까요?int array[0]; g?는 전혀하지 않습니다.GCC를 사용하다

샘플 프로그램

#include <stdio.h>

int main() {
    int arr[0];
    return 0;
}

설명

Darhazer의 코멘트에서 가변 길이와 같이 지적되는 것이 아니라 이렇게 초기화된 제로 렝스 어레이가 최적화되는지 여부를 실제로 알아보려고 합니다.

를 풀어야 에, 그 그래서 제가 그 코드를 풀어야 하는지 알아내려고 합니다.SIZE되어 있습니다.0 정의되어 있는 중 에서 발생합니다.int array[SIZE];

저는 사실 GCC가 불평하지 않는 것에 놀랐고, 그래서 질문하게 되었습니다.제가 들은 답변으로는 경고가 없는 것은 새로운 []구문으로 갱신되지 않은 오래된 코드를 지원하는 것이 가장 큰 원인이라고 생각합니다.

저는 주로 오류가 궁금했기 때문에 Lundin의 답변이 맞다고 태그 붙였습니다(Nawaz의 답변이 처음이었지만, 그렇게 완벽하지는 않았습니다). 다른 사람들은 Tail-Paded 구조의 실제 사용법을 지적하고 있었습니다만, 관련성이 있었습니다만, 제가 찾고 있던 것은 정확히는 아니었습니다.

어레이의 크기가 0일 수 없습니다.

ISO 9899:2011 6.7.6.2:

식이 상수식일 경우 0보다 큰 값을 가져야 한다.

위의 텍스트는 플레인 배열(제1항) 모두에 해당됩니다.VLA(Variable Length Array)의 경우 식 값이 0 이하일 경우 동작은 정의되지 않습니다(문단 5).이것은 C표준의 규범적인 텍스트입니다.컴파일러는 다르게 구현할 수 없습니다.

gcc -std=c99 -pedanticVLA를 사용합니다.

기준대로라면 그것은 허용되지 않는다.

단, C 컴파일러에서는 이러한 선언을 Flexible Array Member(FAM; 플렉시블 어레이 멤버) 선언으로 취급하고 있습니다.

C99 6.7.2.1, §16: 특별한 경우로서 복수의 이름 있는 부재를 가진 구조물의 마지막 요소는 불완전한 배열 타입을 가질 수 있습니다.이것은 플렉시블 배열 부재라고 불립니다.

FAM의 표준 구문은 다음과 같습니다.

struct Array {
  size_t size;
  int content[];
};

그 후 다음과 같이 할당하는 것이 목적입니다.

void foo(size_t x) {
  Array* array = malloc(sizeof(size_t) + x * sizeof(int));

  array->size = x;
  for (size_t i = 0; i != x; ++i) {
    array->content[i] = 0;
  }
}

스태틱하게 사용할 수도 있습니다(gcc 확장).

Array a = { 3, { 1, 2, 3 } };

이것은 테일패드 구조(이 용어는 C99 Standard의 발행보다 이전) 또는 구조 해킹(Joe Wreschnig가 지적한 덕분)이라고도 합니다.

그러나 이 구문은 최근에야 C99에서 표준화(및 그 효과가 보증됨)되었습니다.이전에는 일정한 크기가 필요했습니다.

  • 1휴대할 수 있는 길이었어요.좀 이상하긴 했지만.
  • 0의향표시는 우수하지만 표준이 일부 컴파일러(gcc 포함)에 의해 확장으로 지원되고 있는 한 합법적이지는 않습니다.

테일 연습은 공간이하십시오).malloc)는 일반적으로 스택 사용에는 적합하지 않습니다.

제로렝스 어레이의 또 다른 용도는 가변길이 오브젝트(C99 이전)를 만드는 것입니다.제로렝스 어레이는 []가 0이 없는 플렉시블 어레이와는 다릅니다.

gcc doc에서 인용:

GNU C에서는 제로렝스 배열이 허용됩니다.이 배열은 가변길이 객체의 헤더인 구조의 마지막 요소로 매우 유용합니다.

 struct line {
   int length;
   char contents[0];
 };
 
 struct line *thisline = (struct line *)
   malloc (sizeof (struct line) + this_length);
 thisline->length = this_length;

ISO C99에서는 유연한 어레이 멤버를 사용합니다.이 멤버는 구문과 의미가 약간 다릅니다.

  • 플렉시블 어레이 멤버는 0을 제외하고 콘텐츠[ ]로 작성됩니다.
  • 유연한 어레이 멤버의 유형이 불완전하므로 연산자 크기가 적용되지 않을 수 있습니다.

의 길이 을 들 수 .struct kdbus_itemkdbus.h(Linux 커널 모듈).

이는 완전히 불법이며 항상 그래왔지만 많은 컴파일러들이 오류를 알리는 것을 게을리하고 있습니다.네가 왜 이걸 하고 싶은지 모르겠어.내가 알고 있는 한 가지 용도는 부울에서 컴파일 시간 오류를 트리거하는 것입니다.

char someCondition[ condition ];

ifcondition 시간 에러false emerror가 됩니다.이치노하기 때문에 과 같이 사용하기로

char someCondition[ 2 * condition - 1 ];

이것은 1 또는 -1의 크기를 제공하지만, 저는 -1의 크기를 허용하는 컴파일러를 찾지 못했습니다.

표준으로 제로 사이즈의 어레이를 탑재할 수는 없습니다만, 실제로 가장 인기 있는 컴파일러는 모두 이 기능을 갖추고 있습니다.그래서 왜 안 좋은지 설명해보도록 하겠습니다.

#include <cstdio>

int main() {
    struct A {
        A() {
            printf("A()\n");
        }
        ~A() {
            printf("~A()\n");
        }
        int empty[0];
    };
    A vals[3];
}

나는 인간이 그런 결과를 기대하는 것과 같다.

A()
A()
A()
~A()
~A()
~A()

Clang이 인쇄하는 내용:

A()
~A()

GCC는 다음을 인쇄합니다.

A()
A()
A()

이것은 전혀 이상하기 때문에 가능하면 C++의 빈 어레이를 사용하지 않는 것이 좋습니다.

또한 GNU C에는 확장기능이 있어 C에 제로렝스 배열을 만들 수 있지만, 제가 올바르게 이해한 바로는 적어도 1개의 멤버가 구조 내에 있어야 합니다.그렇지 않으면 C++를 사용하면 위와 같은 매우 이상한 예를 얻을 수 있습니다.

이 주장에 대한 온라인 문서 gcc의 전체 페이지가 있다고 덧붙입니다.

일부 인용문:

GNU C에서는 제로렝스 배열이 허용됩니다.

ISO C90에서는 콘텐츠 길이를 1로 지정해야 합니다.

그리고.

3.0 이전 버전의 GCC에서는 제로렝스 어레이를 유연한 어레이처럼 정적으로 초기화할 수 있었습니다.이러한 경우에 도움이 되는 것 외에, 이후의 데이터가 파손되는 상황에서도 초기화가 가능했습니다.

할 수 있도록

int arr[0] = { 1 };

및 붐:-)

구조체 내에서 제로 사이즈 어레이 선언이 허용된다면 유용할 것입니다.또한 의미론이 (1) 얼라인먼트를 강제하지만 공간을 할당하지 않는 경우, (2) 결과 포인터가 구조체와 같은 메모리 블록 내에 있는 경우 어레이를 인덱싱하는 것은 정의된 동작으로 간주됩니다.이러한 동작은 C 표준에서는 허용되지 않았지만 일부 오래된 컴파일러에서는 빈 괄호로 불완전한 어레이 선언을 허용하는 것이 표준이 되기 전에 허용되었습니다.

일반적으로 1사이즈의 배열을 사용하여 구현되는 구조 해킹은 의심스럽기 때문에 컴파일러가 이를 깨는 것을 자제할 필요가 없다고 생각합니다.예를 들어, 컴파일러가 다음과 같은 정보를 얻을 수 있습니다.int a[1], 그것을 고려하는 것은 그 권리의 범위 내에 있을 것이다.a[i]~하듯이a[0]누군가 구조 해킹의 정렬 문제를 해결하려고 한다면

typedef 구조 {uint32_t 사이즈;
uint8_t data [4]; // 패딩이 구조 크기를 벗어나는 것을 방지하려면 4를 사용합니다.}

컴파일러가 현명해져서 어레이 크기가 실제로 4라고 가정할 수 있습니다.

; 기재된 바와 같이foo = myStruct-> data[i];
; 해석대로 (리틀 엔디안 하드웨어로 상정)foo = (*(uint32_t*) myStruct-> data) >> (i << 3) & 0xFF;

이러한 최적화는 타당할 수 있습니다.특히,myStruct->data와 같은 조작으로 레지스터에 로드할 수 있다myStruct->size표준에서 이러한 최적화를 금지할 수 있는 것은 아무것도 모릅니다만, 물론 4번째 요소 이외의 요소에 액세스 할 것으로 예상되는 코드를 해독할 수 있습니다.

표준 C 및 C++에서는 크기가 0인 어레이는 허용되지 않습니다.

은 GCC로 해주시면 .-pedantic선택.다음과 같이 경고합니다.

zero.c:3:6: warning: ISO C forbids zero-size array 'a' [-pedantic]

C++의 경우 유사한 경고를 보냅니다.

언급URL : https://stackoverflow.com/questions/9722632/what-happens-if-i-define-a-0-size-array-in-c-c

반응형