가변 매개 변수 목록을 사용하는 함수에 대한 사례의 하위 집합을 처리 할 함수에 대한 함수 포인터를 만들려고합니다. 유스 케이스에서는 ...
함수를 특정 매개 변수 목록을 사용하는 함수로 캐스팅하므로 va_list
및 친구들을 처리하지 않고도 다양한 매개 변수를 처리 할 수 있습니다.C에서 가변 인수를 사용하는 함수 포인터에 가변 인수 포인터를 캐스팅하는 것이 안전합니까?
다음 예제 코드에서는 변수 매개 변수가있는 함수를 하드 코드 된 매개 변수 목록이있는 함수로 캐스팅합니다 (반대의 경우도 마찬가지 임). 이 작품 (또는 일하는) 작동하지만, 사용하는 호출 규칙 때문에 우연의 일치인지 모르겠다. (두 개의 다른 x86_64 기반 플랫폼에서 시도해 보았습니다.)
#include <stdio.h>
#include <stdarg.h>
void function1(char* s, ...)
{
va_list ap;
int tmp;
va_start(ap, s);
tmp = va_arg(ap, int);
printf(s, tmp);
va_end(ap);
}
void function2(char* s, int d)
{
printf(s, d);
}
typedef void (*functionX_t)(char*, int);
typedef void (*functionY_t)(char*, ...);
int main(int argc, char* argv[])
{
int x = 42;
/* swap! */
functionX_t functionX = (functionX_t) function1;
functionY_t functionY = (functionY_t) function2;
function1("%d\n", x);
function2("%d\n", x);
functionX("%d\n", x);
functionY("%d\n", x);
return 0;
}
이 정의되지 않은 동작입니까? 그렇다면 누군가가이 방법이 작동하지 않는 플랫폼의 예제를 제공하거나,보다 복잡한 유스 케이스가 주어지면 실패 할 것이라고 예를 들어 조정할 수 있습니까?
편집 : 그것은 여전히 작동
#include <stdio.h>
#include <stdarg.h>
struct crazy
{
float f;
double lf;
int d;
unsigned int ua[2];
char* s;
};
void function1(char* s, ...)
{
va_list ap;
struct crazy c;
va_start(ap, s);
c = va_arg(ap, struct crazy);
printf(s, c.s, c.f, c.lf, c.d, c.ua[0], c.ua[1]);
va_end(ap);
}
void function2(char* s, struct crazy c)
{
printf(s, c.s, c.f, c.lf, c.d, c.ua[0], c.ua[1]);
}
typedef void (*functionX_t)(char*, struct crazy);
typedef void (*functionY_t)(char*, ...);
int main(int argc, char* argv[])
{
struct crazy c =
{
.f = 3.14,
.lf = 3.1415,
.d = -42,
.ua = { 0, 42 },
.s = "this is crazy"
};
/* swap! */
functionX_t functionX = (functionX_t) function1;
functionY_t functionY = (functionY_t) function2;
function1("%s %f %lf %d %u %u\n", c);
function2("%s %f %lf %d %u %u\n", c);
functionX("%s %f %lf %d %u %u\n", c);
functionY("%s %f %lf %d %u %u\n", c);
return 0;
}
:이 코드는 더 복잡 인수를 중단 할 것이라는 암시를 해결하기 위해, 내 예를 연장했다. 누군가가 실패 할 때의 구체적인 예를 지적 할 수 있습니까?
$ gcc -Wall -g -o varargs -O9 varargs.c
$ ./varargs
this is crazy 3.140000 3.141500 -42 0 42
this is crazy 3.140000 3.141500 -42 0 42
this is crazy 3.140000 3.141500 -42 0 42
this is crazy 3.140000 3.141500 -42 0 42
는 "이 정의되지 않은 동작이 있습니까?"(GCC) 대신
0.5
의 제로 예. 호환되지 않는 함수 포인터를 통해 함수를 호출하면 정의되지 않은 동작이 항상 발생합니다. –가변 매개 변수 호출이 사용되는지 여부에 관계없이 매개 변수를 스택에 푸시하는 것이 일관된 방식으로 수행됩니다 (적어도 예제를 통해). 따라서 실제로 사양에 대해 "정의되지 않았"습니까 (또는 언급되지 않았습니까?), 동작은 실제로 일관성이 있지 않습니까? – mpontillo
@Mike : 가변 인수가 아닌 매개 변수는 가능할 때마다 CPU 레지스터를 통해 전달됩니다 (x86 이상). 그들은 스택에 전혀 밀어 넣지 않습니다. 이것이 효과가없는 이유 중 하나입니다. – AnT