2013-04-15 2 views
5

가변 인자 템플릿 printf 함수의 구현이 몇 가지 있습니다. 사방가변 인자 템플릿과 typesafety

void printf(const char* s) { 
    while (*s) { 
    if (*s == '%' && *++s != '%') 
     throw std::runtime_error("invalid format string: missing arguments"); 
    std::cout << *s++; 
    } 
} 

template<typename T, typename... Args> 
void printf(const char* s, const T& value, const Args&... args) { 
    while (*s) { 
    if (*s == '%' && *++s != '%') { 
     std::cout << value; 
     return printf(++s, args...); 
    } 
    std::cout << *s++; 
    } 
    throw std::runtime_error("extra arguments provided to printf"); 
} 

와이 구현은 입력 안전 (가변 인수가 va_arg를 포함) 정상적인 C가되지 않은 상태입니다 있다고한다 : 하나는 이것이다.

왜 그럴까요? 타입 안전성이란 무엇을 의미하며 C printf va_arg보다이 구현이 갖는 이점은 무엇입니까?

+3

이 버전은 형식 플래그에 전혀 신경 쓰지 않고 단지 스트림 운영자를 통해 물건을 인쇄합니다. – Xeo

+1

'T'는 항상 실제로 전달 된 매개 변수의 형식이 될 것이므로 형식이 안전합니다. 표준 printf는 알지 못합니다. –

+1

제쳐두고, 그것은 끔찍한 타입 안전'printf' 구현입니다.형식 지정자를 무시하고 잘못 해석하며 임시 값 이동을 지원하지 않습니다. 간단히 말해서, typesafe 함수이지만, 그것의 이름에도 불구하고'printf'의 유효한 구현이 아닙니다. 좋은 타입 안전'printf'는 안전 할 때'printf'와 똑같이 행동 할 것이고, 대부분의 안전하지 않은 경우에는 정의되지 않은 것을하지 못할 것입니다. – Yakk

답변

4

안전, 또는 형태 보증 인, 프로그램이 제대로 작동 여부를 소스 코드보고 에서 말할 수 있다는 것을 의미한다.

x에 잘 정의 된 값이 있다고 가정하면 진술 문 std::cout << x은 항상 정확합니다 (초기화되지 않은 상태는 아닙니다). 이것은 소스 코드를 보면서 보장 할 수있는 것입니다. 예를 들어, 다음의 코드 또는 런타임 입력에 따라 가 정확하지 않을 수있다 : constrast 바이

은 C가없는 안전 이다

int main(int argc, char * argv[]) 
{ 
    if (argc == 3) 
     printf(argv[1], argv[2]); 
} 

이 올바른 경우에만 있다면 첫 번째 인수는 정확히 하나의 "%s"을 포함하는 유효한 형식 문자열입니다.

즉, 올바른 C 프로그램을 작성할 수는 있지만 코드를 검사하여 정확성을 판단하는 것은 불가능합니다. printf 함수는 그러한 예 중 하나입니다. 보다 일반적으로, 가변 인수를받는 함수는 안전하지 않을 가능성이 높으며 런타임 값을 기반으로 포인터를 캐스팅하는 함수와 마찬가지로 안전하지 않을 수 있습니다.

+0

+1 더 나은 런타임 입력 실행 상태를 위해 그 샘플을 맞추기가 어렵습니다. 그리고 이것에 대한 훌륭한 대답입니다. – WhozCraig

5

variadic 템플릿 버전에 전달하는 모든 인수에 대해 해당 유형이 컴파일 타임에 알려집니다. 이 지식은 기능 내에서 보존됩니다. 각 개체는 과도하게로드 된 cout으로 전달됩니다. 전달 된 각 유형에 대해이 함수에 별도의 오버로드가 있습니다. 즉, int을 전달하면 ostream::operator<<(int)이 호출되고, 이중을 전달하면 ostream::operator<<(double)이 호출됩니다. 다시 한 번 유형이 보존됩니다. 그리고 각 함수는 적절한 방식으로 각 유형을 처리하는 데 특화되어 있습니다. 그것은 타입 안전입니다.

비록 C printf으로 이야기가 다릅니다. 형식은 함수 내부에 보존되지 않습니다. 형식 문자열 (런타임 값일 수 있음)의 내용을 기반으로 알아 내야합니다. 함수는 인수 형식과 일치시키기 위해 올바른 형식 문자열이 전달되었다고 가정해야합니다. 컴파일러는 이것을 시행하지 않습니다.

또 다른 종류의 안전성이 있으며, 이것은 인수의 수입니다. C printf 함수에 너무 적은 인수를 전달하면 형식 문자열과 일치 할만큼 충분하지 않으므로 정의되지 않은 동작이 발생합니다. variadic 템플릿을 사용하여 동일한 작업을 수행하는 경우 예외가 발생하지만 바람직하지는 않지만 진단하기가 훨씬 쉽습니다.