이 있는 문제점을 사용하여 varargs 참고 매개변수
-
03-07-2019 - |
문제
이 코드 조각(요약)...
AnsiString working(AnsiString format,...)
{
va_list argptr;
AnsiString buff;
va_start(argptr, format);
buff.vprintf(format.c_str(), argptr);
va_end(argptr);
return buff;
}
과에 기초하여,그 참조로 전달하는 것은 기본 가능한 경우에,나는 그것을 변경됐어요.
AnsiString broken(const AnsiString &format,...)
{
... the rest, totally identical ...
}
내 호출하는 코드는 다음과 같습니다:-
AnsiString s1, s2;
s1 = working("Hello %s", "World");
s2 = broken("Hello %s", "World");
하지만,s1 담"Hello,"세계는 동안 s2 는"안녕하세요(null)".이라고 생각하는 방식으로 인해 va_start 작동 하지만,나는지 정확히 무슨 일이 일어나고 있는지 확.
해결책
va_start가 확장되는 것을 보면 무슨 일이 일어나고 있는지 알 수 있습니다.
va_start(argptr, format);
(대략)
argptr = (va_list) (&format+1);
형식이 값 유형 인 경우 모든 변형 인수 직전에 스택에 배치됩니다. 형식이 참조 유형 인 경우 주소 만 스택에 배치됩니다. 참조 변수의 주소를 취하면 인수의 주소가 아닌 주소 또는 원래 변수 (이 중단기 전에 생성 된 임시 소송의 경우)를 얻습니다.
전체 수업을 통과하고 싶지 않다면 옵션은 포인터를 지나가거나 더미 논쟁을 가하는 것입니다.
AnsiString working_ptr(const AnsiString *format,...)
{
ASSERT(format != NULL);
va_list argptr;
AnsiString buff;
va_start(argptr, format);
buff.vprintf(format->c_str(), argptr);
va_end(argptr);
return buff;
}
...
AnsiString format = "Hello %s";
s1 = working_ptr(&format, "World");
또는
AnsiString working_dummy(const AnsiString &format, int dummy, ...)
{
va_list argptr;
AnsiString buff;
va_start(argptr, dummy);
buff.vprintf(format.c_str(), argptr);
va_end(argptr);
return buff;
}
...
s1 = working_dummy("Hello %s", 0, "World");
다른 팁
다음은 C ++ 표준 (18.7- 기타 런타임 지원)에 대해 말합니다. va_start()
(강조 광산) :
ISO가 두 번째 매개 변수에 배치하는 제한 사항
va_start()
헤더의 매크로<stdarg.h>
이 국제 표준에서 다릅니다. 매개 변수parmN
함수 정의의 변수 매개 변수 목록에서 가장 오른쪽 매개 변수의 식별자입니다....
). 매개 변수 인 경우parmN
함수, 배열 또는 참조 유형으로 선언됩니다. 또는 매개 변수가없는 인수를 전달할 때 발생하는 유형과 호환되지 않는 유형의 경우 행동은 정의되지 않습니다.
다른 사람들이 언급했듯이, C ++에서 Varargs를 사용하는 것은 비 스트레이트 C 항목 (및 아마도 다른 방식으로)과 함께 사용하면 위험합니다.
즉, 나는 여전히 printf ()를 항상 사용합니다 ...
당신이 원하지 않는 이유 좋은 분석 N0695
C ++ 코딩 표준 (Sutter, Alexandrescu)에 따르면 :
Varargs는 C ++와 함께 사용해서는 안됩니다.
그들은 안전한 유형이 아니며 클래스 유형의 대상에 대해 정의되지 않은 동작을 가지고있어 문제가 발생할 수 있습니다.
내 쉬운 해결 방법은 다음과 같습니다 (Visual C ++ 2010으로 컴파일) :
void not_broken(const string& format,...)
{
va_list argptr;
_asm {
lea eax, [format];
add eax, 4;
mov [argptr], eax;
}
vprintf(format.c_str(), argptr);
}
Side note:
동작한 클래스 형식으로 varargs 인수가 정의되지 않을 수 있습,그러나 그것의 일관에서 제 경험입니다.컴파일러를 밀어 sizeof(클래스)의 클래스의 메모리에 스택입니다.즉,의사 코드:
alloca(sizeof(class));
memcpy(stack, &instance, sizeof(class);
에 대해 정말 흥미로운 이 예제에서 활용되는 매우 창의적인 방법으로,당신은 수 을 통과 하는 인스턴스의 장소에서 LPCTSTR 을 varargs 기능 직접 작동하고 있으며,주 참여합니다.나는 그것을 떠나 운동으로 리더는 방법을 알아들이는 작동합니다.