2015-02-02 1 views
22

: 내가 함수 포인터를 배우고경고 또는 오류없이 함수 포인터가 작동하는 이유는 무엇입니까? 이 호출 알면

error: too few arguments to function ‘pow’ 

및 작업 아래에이 코드를 볼 때 놀랄있어 :

pow(4); 

이 오류 메시지를 생성합니다. 하지만 왜? 하여 컴파일

#include<stdio.h> 
#include<math.h> 

void aux(double (*function)(), double n, double x); 

int main(void) 
{ 
    aux(pow, 4, 2); 

    aux(sqrt, 4, 0); 

    return 0; 
} 

void aux(double (*function)(double), double n, double x) 
{ 
    if(x == 0) 
     printf("\nsqrt(%.2f, %.2f): %f\n", n, x, (*function)(n)); 
    else 
     printf("\npow(%.2f, %.2f): %f\n", n, x, (*function)(n)); 
} 

I는 :

gcc -Wall -Wextra -pedantic -Wconversion -o test test.c -lm 

결과는 다음

pow(4.00, 2.00): 16.000000 

sqrt(4.00, 0.00): 2.000000 

I는 3 aux의 제 호의 세번째 파라미터를 변경하는 경우, 결과의 변화 :

pow(4.00, 3.00): 64.000000 

sqrt(4.00, 0.00): 2.000000 

그리고 또 하나의 질문. 이 경우 함수에 대한 포인터를 선언하고 사용하는 올바른 방법은 무엇입니까?

+0

@SouravGhosh : 그건 문제가 아닙니다. 누락 된'-lm'은 링커 오류를 유발합니다. –

+0

@KeithThompson 맞아. 내 잘못이야. –

+0

@SouravGhosh 사과 할 필요가 없습니다. 단지 부정확하고 산만 한 의견을 삭제하고 계속하십시오. –

답변

37

이 :

void aux(double (*function)(), double n, double x); 

function에 대한 이전 스타일이 아닌 프로토 타입 선언을 사용합니다. 빈 괄호 ()은 함수가 고정되었지만 지정되지 않은 숫자와 유형의 인수를 취한다는 것을 의미합니다.

C는 이전 버전과의 호환성을 위해 이러한 종류의 선언을 허용합니다. 프로토 타입 (매개 변수의 유형을 지정하는 함수 선언)은 1989 년 ANSI C에 의해 도입되었습니다. 이전에는 함수 선언에 매개 변수 유형을 지정할 수 없었고 컴파일러는 호출이 올바른 번호를 전달했는지 여부를 확인할 수 없었습니다. 인수의 유형.

이러한 선언은 "구식"입니다. 즉, 향후 C 표준에서 지원이 제거 될 수 있음을 의미합니다 (단,위원회는 20 년 이상이를 지우지 않고 있습니다). 인수 유형이 잘못된 함수를 호출하면 컴파일러가 진단 할 필요가 없으며 동작은 정의되지 않습니다.

호환성에 대한 규칙은 프로토 타입이 있고 다른 하나는 그렇지 않은 경우 약간 복잡합니다. 이러한 유형 :

double(double)   /* function with one double parameter 
          returning double */ 
double(double, double) /* function with two double parameters 
          returning double */ 

은 서로 호환되지 않습니다,하지만 그들은 있어 모두이 유형과 호환 :

double() /* function with a fixed but unspecified number of parameters 
       returning double */ 

가능에서 진단없이 잘못된 통화를 할 수 있습니다 것입니다 컴파일러.

이 문제를 방지하려면 항상 프로토 타입을를 사용

void aux(double (*function)(double, double), double n, double x); 

을뿐만 아니라 당신은 컴파일러에서 더 나은 진단을받을 수 있나요, 당신이 아닌 프로토 타입 기능을위한 복잡한 호환성 규칙에 대해 걱정할 필요가 없습니다 (호기심이 있다면 N1570 6.7.6에 명시되어 있습니다.3 단락 16).

+2

하나의 인수만으로'pow' 또는'sqrt' 계산을하는 방법에 대해 궁금해하십니까? – haccks

+0

@haccks : 정의되지 않은 동작입니다. –

+6

@ haccks : 영원히 궁금해 할 수 있습니다. 동작은 ** undefined **입니다. 원칙적으로 다음에 프로그램을 실행할 때 변경 될 수 있습니다. 당신은 그것을 예측할 수 없으며 컴파일러가 실제로 생성 한 코드를 검사하기 위해 바이너리를 분해하여 설명 할 수 있습니다. 컴파일러가 다음에 프로그램을 컴파일 할 때 동일한 코드를 생성한다고 가정 할 수 없습니다. –

5

빈 쌍의 괄호 ()수의 모든 매개 변수를 수로 호출 할 수 있지만 함수 자체에는 프로토 타입에 대한 특정 수의 매개 변수가 있음을 C 컴파일러에 알립니다. 따라서 함수 포인터와 함께 사용하고 전달 된 매개 변수의 수와 유형이 지적 된 프로토 타입과 일치하면 모든 것이 작동합니다. 매개 변수 목록을 굶거나 다른 형식의 값을 사용하는 경우 ... 잘 정의되지 않은 동작입니다.

8

기본 앞에 aux()의 프로토 타입을 지정 했으므로 function에 지정된 인수 유형이 없습니다. GCC는 불평을 시작

void aux(double (*function)(double), double n, double x); 

: 당신이로 aux() 프로토 타입을 선언하면

void f(); /* Accepts any number of arguments thanks to K&R C */ 
void g(void); /* No arguments accepted */ 
void h(int); /* Only one integer argument accepted */ 

: 차이를 알아보세요. 기능 aux()에 대한

9

프로토 타입 ...

void aux(double (*function)(), double n, double x); 

는 ... 함수에 대한 포인터 double를 반환 불특정 인수를 받아들이는 것으로 첫 번째 인수를 지정합니다. 이렇게하면 GCC가 main()에서 해당 함수 호출에 대해 일치하지 않는 형식에 대한 경고를 표시하지 않습니다.

그러나 함수 aux()정의은 전달하는 실제 인수와 호환되지 않는 첫 번째 매개 변수에 대해보다 구체적인 형식을 제공합니다. 포인터를 통해 해당 함수를 호출하면 정의되지 않은 의미이 있습니다. 행동이 당신이 원하는 것처럼 보인 것을 포함하여 꽤 많은 일이 일어날 수 있습니다. 당신은 그 행동에 관해서 무엇이든 의지 할 수 없습니다.