배열에서 ptr로 자연 형 붕괴가있는 C의 표준 배열 사용
@Bo Persson은 여기 에 그의 위대한 대답에서 올바르게 설명합니다 .
배열을 매개 변수로 전달할 때
void arraytest(int a[])
정확히 같은 의미
void arraytest(int *a)
그러나 위의 두 가지 형식도 추가하겠습니다.
정확히 같은 의미
void arraytest(int a[0])
정확히 같은 의미
void arraytest(int a[1])
정확히 같은 의미
void arraytest(int a[2])
정확히 같은 의미
void arraytest(int a[1000])
기타
에 대한 입력 매개 변수 유형의 붕괴, 위의 배열 예제의 모든 하나 하나에서int *
, 심지어 빌드 옵션없이 경고 및 오류없이, 호출 할 수 있습니다 -Wall -Wextra -Werror
켜져 (참조 여기 내 REPO를 같이,이 3 빌드 옵션에 대한 자세한 내용은) 이:
int array1[2];
int * array2 = array1;
arraytest(array1);
arraytest(array2);
사실, "크기"값 ( [0]
, [1]
, [2]
, [1000]
배열 매개 변수의 내부 등) 여기에 미적 / 자기 문서의 목적을 위해 분명히 단지이며, 양의 정수 할 수있다 ( size_t
당신이 원하는 내가 생각 입력)!
그러나 실제로는 함수가받을 것으로 예상되는 배열의 최소 크기를 지정하는 데 사용해야합니다. 그래야 코드를 작성할 때 쉽게 추적하고 확인할 수 있습니다. MISRA-C-2012 표준 ( 구매 / 여기 £ 15.00를위한 표준의 236-PG 2012 버전의 PDF를 다운로드 지금까지 상태 (강조 추가)에게로 간다)
규칙 17.5 배열 유형을 갖는 것으로 선언 된 매개 변수에 해당하는 함수 인수는 적절한 수의 요소를 가져야합니다.
...
매개 변수가 지정된 크기의 배열로 선언 된 경우 각 함수 호출의 해당 인수는 최소한 배열만큼 많은 요소가있는 객체를 가리켜 야합니다.
...
함수 매개 변수에 배열 선언자를 사용하면 포인터를 사용하는 것보다 더 명확하게 함수 인터페이스를 지정합니다. 함수에서 예상하는 최소 요소 수는 명시 적으로 명시되어 있지만 포인터로는 불가능합니다.
즉, C 표준이 기술적으로 적용하지 않더라도 명시 적 크기 형식을 사용하는 것이 좋습니다 . 적어도 개발자는 코드를 사용하는 다른 사용자에게 함수가 예상하는 크기 배열을 명확히하는 데 도움이됩니다. 통과해야합니다.
C의 배열에 대한 형식 안전성 강제
@Winger Sendon이 내 대답 아래의 주석에서 지적했듯이 C가 배열 크기 에 따라 배열 유형 을 다르게 처리하도록 할 수 있습니다 !
첫째, 당신은을 사용하여, 단지 내 위의 예제에서 인식해야합니다 int array1[2];
같이 : arraytest(array1);
원인을 array1
자동으로 붕괴에로 int *
. 그러나이 당신이 가지고가는 경우 의 주소 array1
대신과 전화를 arraytest(&array1)
, 당신은 완전히 다른 행동을 얻을! 이제는 int *
! 대신, 유형은 "int 의 크기 2 배열에 대한 포인터" 또는 "int 유형의 크기 2 배열에 대한 포인터 " 를 의미하는 &array1
is 입니다. 따라서 다음과 같이 FORCE C가 배열의 유형 안전성을 확인할 수 있습니다.int (*)[2]
void arraytest(int (*a)[2])
{
}
이 구문은 읽기 어렵지만 함수 포인터 의 구문과 유사합니다 . 온라인 도구, cdecl 규칙은 , 우리에게 그 이야기 int (*a)[2]
수단을 : "INT의 배열이 포인터로 선언" (2 명의 배열에 대한 포인터를 int
들). : 괄호가없는 버전과 혼동하지 마십시오 int * a[2]
수단 : "int와 포인터의 배열이 같은 선언" (이 배열 포인터 에 int
).
이제이 함수 &
는 올바른 크기의 배열에 대한 포인터를 입력 매개 변수로 사용하여 다음과 같이 주소 연산자 ( ) 로 호출해야합니다 .
int array1[2];
arraytest(&array1);
그러나 이것은 경고를 생성합니다.
int array1[2];
arraytest(array1);
여기에서이 코드를 테스트 할 수 있습니다 .
C 컴파일러가이 경고를 오류로 강제로 전환 arraytest(&array1);
하여 항상 올바른 크기 와 유형 ( int array1[2];
이 경우) 의 입력 배열 만 사용하여 호출 -Werror
하도록하려면 빌드 옵션에 추가 하십시오. onlinegdb.com에서 위의 테스트 코드를 실행하는 경우 오른쪽 상단의 톱니 바퀴 아이콘을 클릭하고 "Extra Compiler Flags"를 클릭하여이 옵션을 입력합니다. 이제이 경고는 다음과 같습니다.
main.c:34:15: warning: passing argument 1 of ‘arraytest’ from incompatible pointer type [-Wincompatible-pointer-types]
main.c:24:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’
이 빌드 오류로 바뀝니다.
main.c: In function ‘main’:
main.c:34:15: error: passing argument 1 of ‘arraytest’ from incompatible pointer type [-Werror=incompatible-pointer-types]
arraytest(array1);
^~~~~~
main.c:24:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’
void arraytest(int (*a)[2])
^~~~~~~~~
cc1: all warnings being treated as errors
다음과 같이 주어진 크기의 배열에 대한 "유형 안전"포인터를 만들 수도 있습니다.
int array[2];
int (*array_p)[2] = &array;
...하지만 필자는 이것을 반드시 추천 하지는 않습니다. 언어 구문 복잡성, 장황함, 코드 설계의 어려움이라는 예외적으로 높은 비용으로 모든 곳에서 유형 안전성을 강요하는 데 사용되는 많은 C ++ 익살스러운 행동을 상기시키기 때문입니다. 이전에 여러 번 외쳤습니다 (예 : "C ++에 대한 내 생각"참조 ).
추가 테스트 및 실험은 바로 아래 링크를 참조하십시오.
참고 문헌
위의 링크를 참조하십시오. 또한:
- 내 코드 실험 온라인 : https://onlinegdb.com/B1RsrBDFD