다른 함수에 void(*) 포인터 사용
a를 통해 다양한 인수 목록을 가진 함수에 대한 포인터에 접근하는 것이 합법입니까?void (*f)()포인터?아래 프로그램은 gcc로 경고 없이 컴파일되어 정상적으로 실행되는 것으로 보이는데, 합법적인 C인가요?
#include <stdio.h>
#include <stdlib.h>
typedef void funp();
static void funcall( funp* F, int args, double x)
{
switch( args)
{
case 0: F(); break;
case 1: F(x); break;
}
}
static void fun0( void)
{
printf( "zero\n");
}
static void fun1( double x)
{
printf( "one\t%f\n", x);
}
int main( )
{
funcall( (funp*)fun0, 0, 17.0);
funcall( (funp*)fun1, 1, 17.0);
return EXIT_SUCCESS;
}
제가 정리를 해봤습니다.
gcc -Wpedantic -Wall -Wextra -std=gnu11 -O2 -o ./funp funp.c
정의되지 않은 행동일 것입니다.nargs매개 변수가 함수가 수행한 인수 수와 일치하지 않았는데, 일치하는 것이 있으면 합법적입니까?
이 경우에는 합법적인 통화입니다.
C 표준의 섹션 6.7.6.3p15는 다음과 같이 두 가지 기능 유형을 호환할 수 있도록 하는 것을 설명합니다( 굵은 글씨로 관련 부분).
두 가지 기능 유형이 호환될 경우 두 가지 모두 호환되는 반환 유형을 지정해야 합니다.또한 매개변수 유형 목록이 둘 다 존재하는 경우 매개변수의 수와 타원종단기의 사용에 있어서 일치해야 합니다. 해당 매개변수는 호환 가능한 유형을 가져야 합니다.한 유형에 매개 변수 유형 목록이 있고 다른 유형에 함수 정의에 속하지 않고 빈 식별자 목록이 포함된 함수 선언기가 지정한 경우 매개 변수 목록에는 타원형 종결자가 없어야 하며 각 매개 변수의 유형은 기본 인수 승격의 적용으로 발생하는 유형과 호환되어야 합니다.하나의 유형이 매개 변수 유형 목록을 가지고 있고 다른 유형이 (아마도 비어 있는) 식별자 목록을 포함하는 함수 정의에 의해 지정된 경우, 둘 다 매개 변수의 수에서 일치해야 하며 각 프로토타입 매개 변수의 유형은 유형 o에 대한 기본 인수 승격의 적용으로 인한 유형과 호환되어야 합니다.f 해당 식별자. (형식 호환성 및 합성 형식의 결정에서 함수 또는 배열 형식으로 선언된 각 매개 변수는 조정된 형식을 갖는 것으로 간주되고, 한정된 형식으로 선언된 각 매개 변수는 선언된 형식의 무자격 버전을 갖는 것으로 간주됩니다.)
그래서 당신은.typedef유형 포함:
void()
다음과 같은 유형의 기능:
void(void)
void(double)
두 함수 정의는 타원을 사용하지 않습니다(...첫 번째 조건을 만족하도록 합니다.두 번째 조건으로 기본 인수 승격이 무엇인지 알아보겠습니다.이는 섹션 6.5.2.2p6에 명시되어 있습니다.
호출된 함수를 나타내는 표현식이 프로토타입을 포함하지 않는 유형을 가질 경우, 정수 승격은 각 인수에 대해 수행되고 유형을 가지는 인수에 대해 수행됩니다.
float진급하다, 진급하다, 진급하다, 진급하다, 진급.double. 이를 기본 인수 프로모션이라고 합니다.
첫 번째 함수는 인수가 없으므로 호환됩니다.두 번째 함수는 단일 함수입니다.double기본 인수 프로모션과 일치하므로 호환성도 있습니다.
몇 가지 예를 들어보자면 다음 기능도 호환이 가능합니다.
void f1(long);
void f2(int);
그러나 이는 다음과 같습니다.
void f3(float);
void f4(char);
void f5(short);
또 다른 답변 말씀드리지만, 오늘 보여주신 코드는 유효한 C입니다.그러나 매개 변수 목록이 없는 함수 유형을 사용하기 때문에 향후 어느 시점에서든 변경될 수 있습니다.
6.11 미래의 언어 방향
6.11.6 기능 선언자
1 빈 괄호가 있는 함수 선언자(프로토타입 형식의 매개 변수 유형 선언자가 아님)의 사용은 진부한 기능입니다.
노후화된 기능은 향후 표준 버전에서 제거될 수 있는 기능입니다.따라서 코드가 미래의 증거가 되기를 바란다면 피하는 것이 최선입니다.
@StoryTeller의 답변에서 언급된 것처럼 빈 괄호가 있는 함수 선언자를 사용하는 것은 진부한 기능이지만 다음을 피할 수 있습니다.
#include <stdio.h>
#include <stdlib.h>
typedef void funp(void);
static void funcall( funp* F, int args, double x)
{
switch( args)
{
case 0:
F();
break;
case 1:
{
typedef void fn(double);
((fn *)F)(x);
}
break;
}
}
static void fun0( void)
{
printf( "zero\n");
}
static void fun1( double x)
{
printf( "one\t%f\n", x);
}
int main( void )
{
funcall( (funp*)fun0, 0, 17.0);
funcall( (funp*)fun1, 1, 17.0);
return EXIT_SUCCESS;
}
편집: 변경된 매개 변수 목록main로.void준법을 위하여
질의에 대한 답변:
"게다가, 만약 둘 다 존재한다면, 매개변수 유형 목록은 매개변수의 수에서 일치해야 합니다."는 fun1의 funp와 fun1의 유형이 호환되지 않는다는 것을 의미하는 것으로 보입니다.캐스팅해도 되나요?
대답은 그렇다 입니다. 캐스팅해도 괜찮습니다.C11 초안 6.3.2.3 par8에서:
한 종류의 함수에 대한 포인터를 다른 종류의 함수에 대한 포인터로 변환한 후 다시 되돌릴 수 있습니다. 그 결과는 원래의 포인터와 동일합니다.변환된 포인터를 사용하여 참조된 유형과 호환되지 않는 함수를 호출하는 경우 동작이 정의되지 않습니다.
코드에서, 에 대한 포인터.fun1에 대한 통화에서 다른 함수 포인터 유형으로 변환되었습니다.funcall, 원래의 형태로 다시 변환된 것입니다.funcall전화할 때 사용할 수 있습니다.fun1.
언급URL : https://stackoverflow.com/questions/61933862/using-void-pointers-for-other-functions
'programing' 카테고리의 다른 글
| 선택 쿼리의 결과를 삽입 선택 쿼리의 매개 변수로 사용 (0) | 2023.11.06 |
|---|---|
| Oracle 11g에서 JSON 지원 (0) | 2023.11.06 |
| ANSI(C89/90) C에서 바이트를 나타내는 데 사용할 유형? (0) | 2023.11.06 |
| C에서 곱슬곱슬한 교정기의 이상한 사용 (0) | 2023.11.06 |
| 안드로이드에서 타원 크기란 무엇을 의미합니까? (0) | 2023.11.06 |