2011-04-06 3 views

답변

96

첫째, 일부 standardese (원형 포함)

6.7.5.3 함수 선언자
... ' 배열'과 같은 파라미터
7 선언 '한다 '한정형 포인터가 유형' '으로 조정 된 경우 형식 한정자 (있는 경우)는 배열 형식 deriva의 및 ] 내에 지정된 것입니다. . static이 배열 유형 유도의 및 ]에도 나타나는 경우 해당 함수를 호출 할 때마다 해당 실제 인수 값은 적어도 만큼 배열의 첫 번째 요소에 대한 액세스를 제공해야합니다 크기 표현식에 의해 지정된 요소. 이 T *a을 선언했다 것처럼 그래서, 짧은에, 어떤 함수 매개 변수가 T a[] 또는 T a[N]로 선언

처리됩니다.

그래서 배열 매개 변수가 포인터로 선언 된 것처럼 취급되는 이유는 무엇입니까? 여기에 이유 :

6.3.2.1 Lvalues, 배열, 기능 지정자는 sizeof 운영자 또는 단항 & 연산자의 피연산자, 또는 문자열 리터럴 인 경우를 제외하고
...
3 배열을 초기화하는 데 사용되는 배열의 형식이 ' 유형'인 표현식이 배열 객체 의 초기 요소를 가리키는 포인터 유형이 ' 유형'인 표현식으로 변환 된 인 경우 lvalue가 아닙니다. 배열 객체에 레지스터 저장 클래스가 있으면 동작이 정의되지 않습니다.

다음 코드 감안할 : 해당 유형은 암시 적으로 "10 요소의 배열로 변환되도록

int main(void) 
{ 
    int arr[10]; 
    foo(arr); 
    ... 
} 

호출에 foo 행을 배열 식 arr는 어느 sizeof 또는 &의 피연산자 아니다 int "부터"int에 대한 포인터 "까지의 값은 6.2.3.1/3에 따릅니다. 따라서 foo은 배열 값이 아닌 포인터 값을받습니다.

6.7.5.3/7의 때문에 foo

void foo(int a[]) // or int a[10] 
{ 
    ... 
} 

을 쓸 수 있지만,

void foo(int *a) 
{ 
    ... 
} 

이 따라서, 두 가지 형태가 동일로 해석됩니다.

6.7.5.3/7의 마지막 문장은 C99 도입, 기본적으로 당신이

void foo(int a[static 10]) 
{ 
    ... 
} 

같은 매개 변수 선언이있는 경우 a에 해당하는 실제 매개 변수가 적어도 와 배열해야한다는 것을 의미했다 요소가 10 개 있습니다.

+1

컴파일러가 두 가지 경우에서 다르게 함수 이름을 잘못 mangling하기 때문에 (적어도 이전 버전의 MSVC C++ 컴파일러를 사용하는 경우에는 차이점이 있음) 링크 문제가 발생합니다. 버그 리포트는 http://connect.microsoft.com/VisualStudio/feedback/details/326874/inconsistent-name-mangling-for-functions-accepting-array-and-pointer-parameters에서 "수정 안 함"을 참조하십시오. – greggo

27

차이점은 순전히 구문입니다. C에서는 배열 표기법이 함수 매개 변수에 사용될 때 자동으로 포인터 선언으로 변환됩니다.

+1

@ Kaushik :이 경우에도 동일하지만 일반적으로는 동일하지 않습니다 (http://stackoverflow.com/questions/2096448/do-these-statements-about). -pointers-have-the-effect) –

+0

@BlueRaja : 예, C의 함정 중 하나입니다. 함수 매개 변수의 선언은 지역 변수의 선언과 매우 유사하지만 약간의 차이점이 있습니다 (예 : 이 배열 - 포인터 자동 변환과 같이) 부주의 한 프로그래머를 물들이는 경향이있다. –

-2

아니요, 차이는 없습니다. 나는 IDA의 바이너리 파일을 모두 호출 버전의 .exe로 주요 기능을 분해 할 때

#include <stdio.h> 

void function(int* array) { 
    int a =5; 
} 

void main() { 
    int array[]={2,4}; 
    function(array); 
    getch(); 
} 

내가 정확히 같은 어셈블리 코드를 아래와 같이 얻을 : (와 Mingw) 컴파일러 ++ 내가 데브 C이 C 코드를 작성 테스트하려면 :

push ebp 
mov  ebp, esp 
sub  esp, 18h 
and  esp, 0FFFFFFF0h 
mov  eax, 0 
add  eax, 0Fh 
add  eax, 0Fh 
shr  eax, 4 
shl  eax, 4 
mov  [ebp+var_C], eax 
mov  eax, [ebp+var_C] 
call sub_401730 
call sub_4013D0 
mov  [ebp+var_8], 2 
mov  [ebp+var_4], 4 
lea  eax, [ebp+var_8] 
mov  [esp+18h+var_18], eax 
call sub_401290 
call _getch 
leave 
retn 

그래서이 호출의 두 버전 사이의 차이, 적어도 컴파일러 위협을 똑같이이 없습니다.

+15

죄송합니다. 그러나 이것은 gcc의 일부 버전이 둘 다 x86에서 동일한 어셈블리를 생성한다는 것을 증명합니다. 정답, 잘못된 설명. – lambdapower

관련 문제