size_t 유형의 변수에 대한 교차 플랫폼 형식 문자열?
크로스 플랫폼 c/c++ 프로젝트(Win32, Linux, OSX)에서 *printf 함수를 사용하여 size_t 타입의 변수를 인쇄해야 합니다.어떤 환경에서는 size_t가 8바이트이고 어떤 환경에서는 4바이트입니다.glibc에서는 %zd를 사용하고 Win32에서는 %Id를 사용할 수 있습니다.이 문제를 해결할 수 있는 우아한 방법이 있을까요?
PRIuPTR
macroo(<inttype에서))에서는 h>)의 합니다.uintptr_t
a, 이 할 이 할 size_t
예를 들어, 자르지 않고 사용할 수 있습니다.
fprintf(stream, "Your size_t var has value %" PRIuPTR ".", (uintptr_t) your_var);
여기 정말 두 가지 질문이 있습니다.첫 번째 질문은 세 개의 플랫폼에 맞는 인쇄물 지정자 문자열이냐는 것입니다.:size_t
는 부호가 없는 형식입니다.
Windows에서 "을(를) 사용합니다.%Iu
".
Linux 및 OSX에서는 "을(를) 사용합니다.%zu
".
두 번째 질문은 포맷 스트링과 같은 것들이 플랫폼마다 다를 수 있다는 것을 고려할 때, 어떻게 여러 플랫폼을 지원할 것인가 하는 것입니다.다른 사람들이 지적한 것처럼, 사용하는 것은#ifdef
금방 못생겨집니다.
대신 대상 플랫폼별로 별도의 makefile이나 프로젝트 파일을 작성합니다.그런 다음 소스 파일의 매크로 이름을 기준으로 지정자를 참조하여 각 makefile에 매크로를 적절하게 정의합니다.특히 GCC와 Visual Studio 모두 'D' 스위치를 사용하여 명령줄에 매크로를 정의합니다.
빌드 시스템이 매우 복잡하다면(여러 빌드 옵션, 생성된 소스 등), 3개의 개별 메이크 파일을 유지하는 것이 무리일 수 있으며, CMake나 GNU 자동 도구와 같은 일종의 고급 빌드 시스템을 사용해야 합니다.그러나 기본 원리는 동일합니다. 소스 파일에 플랫폼 탐지 로직을 넣는 대신 빌드 시스템을 사용하여 플랫폼별 매크로를 정의합니다.
제가 생각할 수 있는 유일한 것은 전형적인 것입니다.
#ifdef __WIN32__ // or whatever
#define SSIZET_FMT "%ld"
#else
#define SSIZET_FMT "%zd"
#endif
그리고 나서 일정한 접힘의 이점을 활용합니다.
fprintf(stream, "Your size_t var has value " SSIZET_FMT ".", your_var);
Dan Saks는 Embedded Systems Design에 이 문제를 다룬 기사를 썼습니다.Dan에 따르면 %zu가 표준 방식이지만 이를 지원하는 컴파일러는 거의 없었습니다.대안으로 %lu를 명시적인 인수 캐스트와 함께 사용할 것을 권장했습니다.
size_t n; ... printf("%lu", (unsigned long)n);
사용하다boost::format
. 타이프 세이프라 프린트가 가능합니다.size_t
%d
, 또한 당신은 기억할 필요가 없습니다.c_str()
위에std::string
할 때, 에게 해도,%s
아니면 그 반대면 효과가 있을 겁니다
만족스러운 해결책은 없지만, size_t 항목을 문자열로 포맷하고 문자열을 인쇄하는 전문 기능을 고려해 볼 수 있습니다.
(또는 사용자가 피할 수 있다면 boost::format을 사용하면 이러한 작업을 쉽게 처리할 수 있습니다.)
저장 클래스가 가장 큰 정수 유형을 찾아서 값을 지정한 다음 큰 유형에 적합한 형식 문자열을 사용하면 됩니다.이 솔루션은 size_t뿐만 아니라 모든 유형(ptrdiff_t 등)에 적용됩니다.
당신이 사용하고 싶은 것은 uintmax_t와 macro priuMAX 포맷입니다.Visual C++의 경우 c99 호환 stdint.handinttype을 다운로드해야 합니다.마이크로소프트에서 제공하지 않기 때문입니다.
참고
http://www.embedded.com/columns/technicalinsights/204700432
이 기사는 프레데리코가 인용한 기사의 오류를 수정한 것입니다.
옵션 1(크로스 플랫폼 사용에 가장 적합하고 강력한 답변):inttypes.h
을 이용하여 해킹하다PRIuPTR
지정자
에서, 는 ( 에서 의 에서 PRIuPTR
(부호화되지 않은 포인터) intttypes.h의 printf 형식 문자열은 다음을 유지할 수 있을 정도로 깁니다.size_t
다음 정의를 사용하여하는,을다를음다reged형,를,gs음size_t
stringsprintf식다입니다 .
그러나 C 및 C++ 언어 표준에서는 이를 적용하지 않으므로 특정 아키텍처(컴파일러, 하드웨어 등)에서 이 기능이 작동하는지 확인하는 것이 중요합니다.
#include <inttypes.h>
// Custom printf format strings for `size_t` variable types, which are nearly
// always the same size as pointers on any given architecture (though this is
// NOT enforced by the standard!)
//
// `size_t` is an unsigned decimal integer (ex: usually 8 bytes on a 64-bit
// system, 4 bytes on a 32-bit system, or 2 bytes on an 8-bit system) so you
// can simply print it as though it was a pointer!:
#define PRIuSZT PRIuPTR // u = unsigned decimal integer
#define PRIxSZT PRIxPTR // x = unsigned decimal integer in lower-case hex
#define PRIXSZT PRIXPTR // X = unsigned decimal integer in upper-case hex
#define PRIoSZT PRIoPTR // o = unsigned decimal integer in octal
// The above representations make the most sense. Other representations are
// below, though these will interpret the `size_t` type as though it was
// signed, which doesn't make much sense, since it's not:
#define PRIdSZT PRIdPTR // d = signed decimal integer
#define PRIiSZT PRIiPTR // i = signed decimal integer
// For `ssize_t` (signed size_t) types, however, the d and i specifiers *do*
// make sense, so you could do this:
#define PRIdSSZT PRIdPTR // d = signed decimal integer
#define PRIiSSZT PRIiPTR // i = signed decimal integer
은 의 인 은 를 하는 을 합니다 합니다 을 하는 의 은 인 를 size_t
다양한 표현을 입력합니다.
size_t my_variable = 123456789;
// print the `size_t` type as an unsigned decimal integer
printf("%" PRIuSZT "\n", my_variable);
// print the `size_t` type as an unsigned decimal integer in lower-case hex
printf("0x%" PRIxSZT "\n", my_variable);
// print the `size_t` type as an unsigned decimal integer in upper-case hex
printf("0X%" PRIXSZT "\n", my_variable);
// print the `size_t` type as an unsigned decimal integer in octal
printf("0%" PRIoSZT "\n", my_variable);
// Print the hex values again, this time with leading zero-padding to print a
// full 8-bytes (16 chars) worth of data
printf("\n");
printf("0x%016" PRIxSZT "\n", my_variable); // lower-case unsigned hex
printf("0X%016" PRIXSZT "\n", my_variable); // upper-case unsigned hex
// Print the octal value again, this time with leading zero-padding to print a
// full 8-bytes (22 chars) worth of data
printf("\n");
printf("0%022" PRIoSZT "\n", my_variable); // unsigned octal
64비트 Linux 시스템에서의 출력 예:
123456789
0x75bcd15
0X75BCD15
0726746425
0x00000000075bcd15
0X00000000075BCD15
00000000000000726746425
2: 2 사용: %zu
그것이 뒷받침되는 곳에
로 사용하는 에서는 "Gcc"와 "STM32"가 .%z
길이 지정자가 반드시 구현되는 것은 아니며, 다음과 같은 작업을 수행합니다.printf("%zu\n", my_size_t_num);
단순히 문자를 출력하는 것으로 끝날지도 모릅니다.%zu
(개인적으로 테스트를 해보니 사실이었습니다.) 당신의 가치 대신에size_t
변수.
그러나 가능한 경우에는 그냥 사용합니다.%zu
다음과 같이, "z" 길이 지정자:size_t
선택사항:
사용 예시:
size_t my_variable = 123456789;
printf("%zu\n", my_variable);
옵션 3(이후 작동이 사실상 보장됨)uint64_t
알려진 모든 것을 담을 수 있을 만큼 충분히 큽니다.size_t
기존의 모든 아키텍처에 대한 types)inttypes.h
PRIu64
더 구체적으로, 당신을 캐스팅하는 것과 함께.size_t
에 가변적인uint64_t
인쇄하기 전에
그러나 모든 아키텍처에서 작동하는 것을 보장하기 위해 필요한 경우 또는 특정 아키텍처에 대해 확신할 수 없는 경우에는 주조 및 인쇄만 가능합니다.uint64_t
이 작업은 모든 시스템에서 작동할 것이 사실상 보장되지만 주조 단계가 추가로 필요하기 때문에 소규모 아키텍처에서는 불필요하게 필요 이상의 크기(필요 이상의 프로세서 명령을 필요로 함)로 주조할 수 있습니다.
사용 예시:
#include <stdint.h> // for uint64_t
#include <inttypes.h> // for PRIu64
size_t my_variable = 123456789;
// print the `size_t` type as an unsigned decimal integer
printf("%" PRIu64 "\n", (uint64_t)my_variable);
// print the `size_t` type as an unsigned decimal integer in lower-case hex
printf("0x%" PRIx64 "\n", (uint64_t)my_variable);
// print the `size_t` type as an unsigned decimal integer in upper-case hex
printf("0X%" PRIX64 "\n", (uint64_t)my_variable);
// etc etc. See the Option 1 examples and follow the same patterns.
위의 3가지 옵션을 모두 보여주는 전체 예시 프로그램
나의 eRCaGuy_hello_world repo에서:
print_size_t.c(C와 C++에서 모두 완벽하게 실행됨):
#include <stdio.h>
#include <inttypes.h>
// Custom printf format strings for `size_t` variable types, which are nearly
// always the same size as pointers on any given architecture (though this is
// NOT enforced by the standard!)
//
// `size_t` is an unsigned decimal integer (ex: usually 8 bytes on a 64-bit
// system, 4 bytes on a 32-bit system, or 2 bytes on an 8-bit system) so you
// can simply print it as though it was a pointer!:
#define PRIuSZT PRIuPTR // u = unsigned decimal integer
#define PRIxSZT PRIxPTR // x = unsigned decimal integer in lower-case hex
#define PRIXSZT PRIXPTR // X = unsigned decimal integer in upper-case hex
#define PRIoSZT PRIoPTR // o = unsigned decimal integer in octal
// The above representations make the most sense. Other representations are
// below, though these will interpret the `size_t` type as though it was
// signed, which doesn't make much sense, since it's not:
#define PRIdSZT PRIdPTR // d = signed decimal integer
#define PRIiSZT PRIiPTR // i = signed decimal integer
// For `ssize_t` (signed size_t) types, however, the d and i specifiers *do*
// make sense, so you could do this:
#define PRIdSSZT PRIdPTR // d = signed decimal integer
#define PRIiSSZT PRIiPTR // i = signed decimal integer
int main()
{
printf("Hello World\n");
size_t my_variable = 123456789;
printf("sizeof(my_variable) = %" PRIuSZT "\n", sizeof(my_variable));
// -------------------------------------------------------------------------
// Option 1 (best and most-robust answer for cross-platform usage):
// `inttypes.h` hack using `PRIuPTR` type specifiers
// -------------------------------------------------------------------------
printf("\n===== Option 1 =====\n");
// print the `size_t` type as an unsigned decimal integer
printf("%" PRIuSZT "\n", my_variable);
// print the `size_t` type as an unsigned decimal integer in lower-case hex
printf("0x%" PRIxSZT "\n", my_variable);
// print the `size_t` type as an unsigned decimal integer in upper-case hex
printf("0X%" PRIXSZT "\n", my_variable);
// print the `size_t` type as an unsigned decimal integer in octal
printf("0%" PRIoSZT "\n", my_variable);
// Print the hex values again, this time with leading zero-padding to print
// a full 8-bytes (16 chars) worth of data
printf("\n");
printf("0x%016" PRIxSZT "\n", my_variable); // lower-case unsigned hex
printf("0X%016" PRIXSZT "\n", my_variable); // upper-case unsigned hex
// Print the octal value again, this time with leading zero-padding to print
// a full 8-bytes (22 chars) worth of data
printf("\n");
printf("0%022" PRIoSZT "\n", my_variable); // unsigned octal
// -------------------------------------------------------------------------
// Option 2: use `%zu` where it is supported
// -------------------------------------------------------------------------
printf("\n===== Option 2 =====\n");
printf("%zu\n", my_variable);
// -------------------------------------------------------------------------
// Option 3 (virtually guaranteed to work since `uint64_t` is large enough
// to hold all known `size_t` types on all existing architectures): use the
// `inttypes.h` `PRIu64` specifier, with the addition of casting your
// `size_t` variable to `uint64_t` before printing
// -------------------------------------------------------------------------
printf("\n===== Option 3 =====\n");
// print the `size_t` type as an unsigned decimal integer
printf("%" PRIu64 "\n", (uint64_t)my_variable);
// print the `size_t` type as an unsigned decimal integer in lower-case hex
printf("0x%" PRIx64 "\n", (uint64_t)my_variable);
// print the `size_t` type as an unsigned decimal integer in upper-case hex
printf("0X%" PRIX64 "\n", (uint64_t)my_variable);
// etc etc. See the Option 1 examples and follow the same patterns.
return 0;
}
실행 및 출력 예제:
eRCaGuy_hello_world/c$ gcc -Wall -Wextra -Werror -O3 -std=gnu17 print_size_t.c -o bin/a -lm && bin/a
Hello World
sizeof(my_variable) = 8
===== Option 1 =====
123456789
0x75bcd15
0X75BCD15
0726746425
0x00000000075bcd15
0X00000000075BCD15
00000000000000726746425
===== Option 2 =====
123456789
===== Option 3 =====
123456789
0x75bcd15
0X75BCD15
출처 인용:
- http://www.cplusplus.com/reference/cstdio/printf/
- http://www.cplusplus.com/reference/cinttypes/
- http://www.cplusplus.com/reference/cstdint/
이 문제에 대한 제 선택은 단순히 size_t 인수를 부호 없는 긴 길이로 캐스팅하고 %lu를 모든 곳에 사용하는 것입니다. 물론 이 값이 2^32-1을 초과하지 않을 것으로 예상되는 경우에만 해당됩니다.이 길이가 너무 짧을 경우 항상 부호 없는 긴 길이로 캐스팅하여 %llu로 포맷할 수 있습니다.
어느 쪽이든, 당신의 끈은 절대 어색하지 않을 겁니다.
size_t
16비트 이상의 부호 없는 유형입니다.폭이 32와 64인 경우가 많습니다.
printf("%zu\n", some_size_t_object); // Standard since C99
앞으로 가장 좋은 방법이지만 코드가 C99 이전 플랫폼으로 포팅해야 할 경우 값을 넓은 유형으로 숨겨야 합니다.unsigned long
합리적인 후보인지는 몰라도 부족할 수도 있습니다.
// OK, yet insufficient with large sizes > ULONG_MAX
printf("%lu\n", (unsigned long) some_size_t_object);
조건부 코드를 사용하거나
#ifdef ULLONG_MAX
printf("%llu\n", (unsigned long long) some_size_t_object);
#else
printf("%lu\n", (unsigned long) some_size_t_object);
#endif
마지막으로 고려해보세요.double
. 다소 비효율적이지만 무어의 법칙을 고려할 때 2030년에서 2040년까지 모든 고대 및 새로운 플랫폼을 처리해야 합니다.double
정확한 결과가 없을 수도 있습니다.
printf("%.0f\n", (double) some_size_t_object);
언급URL : https://stackoverflow.com/questions/174612/cross-platform-format-string-for-variables-of-type-size-t
'programing' 카테고리의 다른 글
$($).wtclick', '#id', 함수({}) 대 $('#id'.wtclick', 함수({}) (0) | 2023.09.15 |
---|---|
문자열에 붙여넣기 (0) | 2023.09.15 |
비트 조작 모범 사례 (0) | 2023.09.15 |
Android Data Binding이 인수를 onClick 메서드에 전달합니다. (0) | 2023.09.15 |
큰 요청에 대해 응답 헤더를 업스트림에서 읽는 동안 Nginx 업스트림이 너무 일찍 닫혔습니다. (0) | 2023.09.15 |