C ++에서 printf size_t에 대한 깨끗한 코드 (또는 : C ++에서 C99의 % z에 가장 근접 함) 좋은 것을 유지하면서 가짜 컴파일러

다음을 인쇄하는 C ++ 코드가 있습니다 size_t.

size_t a;
printf("%lu", a);

32 비트 및 64 비트 아키텍처 모두에서 경고없이 컴파일하고 싶습니다.

이것이 C99라면 printf("%z", a);. 그러나 AFAICT %z는 표준 C ++ 방언에는 존재하지 않습니다. 그래서 대신에

printf("%lu", (unsigned long) a);

정말 추합니다.

size_t언어에 내장 된 s 를 인쇄 할 수있는 기능이 없다면 size_t, 좋은 것을 유지하면서 가짜 컴파일러 경고를 제거하기 위해 s에 적절한 캐스트를 삽입 할 printf 래퍼를 작성하는 것이 가능한지 궁금 합니다.

어떤 아이디어?


편집 내가 printf를 사용하는 이유를 명확히하기 위해 : 나는 정리하고있는 비교적 큰 코드베이스를 가지고 있습니다. printf 래퍼를 사용하여 “경고를 작성하고, 파일에 기록하고, 오류와 함께 코드를 종료”와 같은 작업을 수행합니다. cout 래퍼로이 작업을 수행하기에 충분한 C ++-foo를 수집 할 수 있지만 컴파일러 경고를 제거하기 위해 프로그램의 모든 warn () 호출을 변경하는 것은 아닙니다.



답변

대부분의 컴파일러에는 자체 지정자 size_tptrdiff_t인수가 있습니다. 예를 들어 Visual C ++는 각각 % Iu와 % Id를 사용합니다. gcc를 사용하면 % zu 및 % zd를 사용할 수 있다고 생각합니다.

매크로를 만들 수 있습니다.

#if defined(_MSC_VER) || defined(__MINGW32__) //__MINGW32__ should goes before __GNUC__
  #define JL_SIZE_T_SPECIFIER    "%Iu"
  #define JL_SSIZE_T_SPECIFIER   "%Id"
  #define JL_PTRDIFF_T_SPECIFIER "%Id"
#elif defined(__GNUC__)
  #define JL_SIZE_T_SPECIFIER    "%zu"
  #define JL_SSIZE_T_SPECIFIER   "%zd"
  #define JL_PTRDIFF_T_SPECIFIER "%zd"
#else
  // TODO figure out which to use.
  #if NUMBITS == 32
    #define JL_SIZE_T_SPECIFIER    something_unsigned
    #define JL_SSIZE_T_SPECIFIER   something_signed
    #define JL_PTRDIFF_T_SPECIFIER something_signed
  #else
    #define JL_SIZE_T_SPECIFIER    something_bigger_unsigned
    #define JL_SSIZE_T_SPECIFIER   something_bigger_signed
    #define JL_PTRDIFF_T_SPECIFIER something-bigger_signed
  #endif
#endif

용법:

size_t a;
printf(JL_SIZE_T_SPECIFIER, a);
printf("The size of a is " JL_SIZE_T_SPECIFIER " bytes", a);


답변

printf형식 지정은 %zuC ++ 시스템에서 잘 작동합니다; 더 복잡하게 만들 필요가 없습니다.


답변

C ++ 11

C ++ 11 std::printf은 C99를 가져 오므로 C99 %zu형식 지정자를 지원해야 합니다.

C ++ 98

대부분의 플랫폼에서, size_t그리고 uintptr_t당신이 사용할 수있는 경우, 동일 PRIuPTR에 정의 된 매크로를 <cinttypes>:

size_t a = 42;
printf("If the answer is %" PRIuPTR " then what is the question?\n", a);

당신이 경우 정말 안전하려면, 캐스팅 uintmax_t및 사용 PRIuMAX:

printf("If the answer is %" PRIuMAX " then what is the question?\n", static_cast<uintmax_t>(a));


답변

Windows 및 Visual Studio의 printf 구현에서

 %Iu

나를 위해 작동합니다. msdn 참조


답변

C ++를 사용하고 있으므로 IOStreams를 사용하지 않는 이유는 무엇입니까? 당신은 정의하지 않습니다 뇌사 C ++ 구현을 사용하지 않는로 즉 한, 경고없이 컴파일하고 오른쪽 종류를 인식하는 일을해야합니다 operator <<위해를 size_t.

실제 출력이으로 완료되어야 printf()하는 경우에도이를 IOStreams와 결합하여 유형 안전 동작을 얻을 수 있습니다.

size_t foo = bar;
ostringstream os;
os << foo;
printf("%s", os.str().c_str());

매우 효율적이지는 않지만 위의 사례는 파일 I / O를 다루기 때문에이 문자열 형식화 코드가 아닌 병목 현상입니다.


답변

여기에 가능한 해결책이 있지만 꽤 좋은 해결책은 아닙니다 ..

template< class T >
struct GetPrintfID
{
  static const char* id;
};

template< class T >
const char* GetPrintfID< T >::id = "%u";


template<>
struct GetPrintfID< unsigned long long > //or whatever the 64bit unsigned is called..
{
  static const char* id;
};

const char* GetPrintfID< unsigned long long >::id = "%lu";

//should be repeated for any type size_t can ever have


printf( GetPrintfID< size_t >::id, sizeof( x ) );


답변

FMT 라이브러리 의 빠른 휴대용 (안전) 구현을 제공 printf포함 z개질제를 size_t:

#include "fmt/printf.h"

size_t a = 42;

int main() {
  fmt::printf("%zu", a);
}

또한 Python과 유사한 형식 문자열 구문을 지원하고 유형 정보를 캡처하므로 수동으로 제공 할 필요가 없습니다.

fmt::print("{}", a);

주요 컴파일러로 테스트되었으며 플랫폼간에 일관된 출력을 제공합니다.

부인 성명 : 저는이 도서관의 저자입니다.