diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 9016c5734..cfbfe1565 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -665,8 +665,7 @@ static void terminate_pending_irp_threads(SERIAL_DEVICE* serial) } CloseHandle(irpThread); - WLog_Print(serial->log, WLOG_DEBUG, "IRP thread terminated, CompletionId %"PRIuz"", - id); + WLog_Print(serial->log, WLOG_DEBUG, "IRP thread terminated, CompletionId %p", (void*) id); } ListDictionary_Clear(serial->IrpThreads); diff --git a/docs/PrintFormatSpecifiers.md b/docs/PrintFormatSpecifiers.md new file mode 100644 index 000000000..1182f84be --- /dev/null +++ b/docs/PrintFormatSpecifiers.md @@ -0,0 +1,131 @@ +# Print Format Specifiers + +## Lookup Table + +We use the following format specifiers for all \*printf\* and WLog_* functions: + +| Type | signed | unsigned | octal | hex | HEX | +| ------------------ | --------- | --------- | --------- | --------- | --------- | +| signed char | %hhd | | | | | +| unsigned char | | %hhu | %hho | %hhx | %hhX | +| short | %hd | | | | | +| unsigned short | | %hu | %ho | %hx | %hX | +| int | %d | | | | | +| unsigned int | | %u | %o | %x | %X | +| long | %ld | | | | | +| unsigned long | | %lu | %lo | %lx | %lX | +| long long | %lld | | | | | +| unsigned long long | | %llu | %llo | %llx | %llX | +| size_t | | %"PRIuz" | %"PRIoz" | %"PRIxz" | %"PRIXz" | +| INT8 | %"PRId8" | | | | | +| UINT8 | | %"PRIu8" | %"PRIo8" | %"PRIx8" | %"PRIX8" | +| BOOLEAN | | %"PRIu8" | %"PRIo8" | %"PRIx8" | %"PRIX8" | +| BYTE | | %"PRIu8" | %"PRIo8" | %"PRIx8" | %"PRIX8" | +| CHAR | %"PRId8" | | | | | +| UCHAR | | %"PRIu8" | %"PRIo8" | %"PRIx8" | %"PRIX8" | +| INT16 | %"PRId16" | | | | | +| UINT16 | | %"PRIu16" | %"PRIo16" | %"PRIx16" | %"PRIX16" | +| WORD | | %"PRIu16" | %"PRIo16" | %"PRIx16" | %"PRIX16" | +| WCHAR | | %"PRIu16" | %"PRIo16" | %"PRIx16" | %"PRIX16" | +| SHORT | %"PRId16" | | | | | +| USHORT | | %"PRIu16" | %"PRIo16" | %"PRIx16" | %"PRIX16" | +| INT32 | %"PRId32" | | | | | +| UINT32 | | %"PRIu32" | %"PRIo32" | %"PRIx32" | %"PRIX32" | +| INT | %"PRId32" | | | | | +| UINT | | %"PRIu32" | %"PRIo32" | %"PRIx32" | %"PRIX32" | +| LONG | %"PRId32" | | | | | +| HRESULT | %"PRId32" | | | %"PRIx32" | %"PRIX32" | +| NTSTATUS | %"PRId32" | | | %"PRIx32" | %"PRIX32" | +| ULONG | | %"PRIu32" | %"PRIo32" | %"PRIx32" | %"PRIX32" | +| DWORD | | %"PRIu32" | %"PRIo32" | %"PRIx32" | %"PRIX32" | +| DWORD32 | | %"PRIu32" | %"PRIo32" | %"PRIx32" | %"PRIX32" | +| BOOL | %"PRId32" | | | | | +| INT64 | %"PRId64" | | | | | +| LONG64 | %"PRId64" | | | | | +| LONGLONG | %"PRId64" | | | | | +| UINT64 | | %"PRIu64" | %"PRIo64" | %"PRIx64" | %"PRIX64" | +| ULONG64 | | %"PRIu64" | %"PRIo64" | %"PRIx64" | %"PRIX64" | +| ULONGLONG | | %"PRIu64" | %"PRIo64" | %"PRIx64" | %"PRIX64" | +| DWORDLONG | | %"PRIu64" | %"PRIo64" | %"PRIx64" | %"PRIX64" | +| QWORD | | %"PRIu64" | %"PRIo64" | %"PRIx64" | %"PRIX64" | +| ULONG64 | | %"PRIu64" | %"PRIo64" | %"PRIx64" | %"PRIX64" | + + +## Pointers + +When printing pointers you should cast the argument to ``(void*)``: + +```c +rdpContext *pContext; +fprintf(stderr, "rdp context is %p\n", (void*) pContext); +``` + +If you need more formatting options cast the pointer argument to `size_t` and use +any %"PRI*z" format specifier: + +```c +rdpContext *pContext; +fprintf(stderr, "rdp context is %" PRIuz " (0x%" PRIXz ")\n", (size_t) pContext, (size_t) pContext); +``` + + +## Integer Promotion + +Remember that integer types smaller than int are promoted when an operation is +performed on them. + +Wrong: + +```c +UINT8 a, b; +fprintf(stderr, "a - b is %" PRIu8 "\n", a - b); +// depending on the system's PRIu8 definition you might get: +// warning: format specifies type 'unsigned char' but the argument has type 'int' +``` + +Correct: + +```c +UINT8 a, b; +fprintf(stderr, "a - b is %d\n", a - b); +// or ... +fprintf(stderr, "a - b is %" PRIu8 "\n", (UINT8) (a - b)); +``` + +## TCHAR + +When using `_tprintf` or similar TCHAR formatting functions or macros you +need to enclose the PRI format defines: + +```c +LPCTSTR lpFileName1; +UINT64 fileSize1; + +_tprintf(_T("The size of %s is %") _T(PRIu64) _T("\n"), lpFileName1, fileSize1); +``` + +Since this makes the strings a lot harder to read try to avoid _tprintf if the +arguments don't contain TCHAR types. + +Note: If all compilers were C99 compliant we could simply write ... + +```c +_tprintf(_T("The size of %s is %") PRIu64 "\n"), lpFileName1, fileSize1); +``` + +... since the standard says that only one of the character sequences must be +prefixed by an encoding prefix and the rest of them are treated to have the +same. However, Microsoft Visual Studio versions older than VS 2015 are not C99 +compliant in this regard. + +See [How to use stdint types with _tprintf in Visual Studio 2013](http://stackoverflow.com/questions/41126081/how-to-use-stdint-types-with-tprintf-in-visual-studio-2013) +for more information. + + + +## Links + +- [[MS-DTYP] 2.2 Common Data Types](https://msdn.microsoft.com/en-us/library/cc230309.aspx) +- [Understand integer conversion rules](https://www.securecoding.cert.org/confluence/display/c/INT02-C.+Understand+integer+conversion+rules) +- [Printf format strings](https://en.wikipedia.org/wiki/Printf_format_string) +- [C data types - Basic Types](https://en.wikipedia.org/wiki/C_data_types#Basic_types) diff --git a/winpr/libwinpr/clipboard/synthetic.c b/winpr/libwinpr/clipboard/synthetic.c index 421b94e00..718d01c04 100644 --- a/winpr/libwinpr/clipboard/synthetic.c +++ b/winpr/libwinpr/clipboard/synthetic.c @@ -382,7 +382,7 @@ static void* clipboard_synthesize_html_format(wClipboard* clipboard, UINT32 form body = strstr(pSrcData, ""); /* StartFragment */ - sprintf_s(num, sizeof(num), "%010lu", strlen(pDstData)); + sprintf_s(num, sizeof(num), "%010"PRIuz"", strlen(pDstData)); CopyMemory(&pDstData[69], num, 10); strcat(pDstData, pSrcData); /* EndFragment */ - sprintf_s(num, sizeof(num), "%010lu", strlen(pDstData)); + sprintf_s(num, sizeof(num), "%010"PRIuz"", strlen(pDstData)); CopyMemory(&pDstData[93], num, 10); strcat(pDstData, ""); @@ -404,7 +404,7 @@ static void* clipboard_synthesize_html_format(wClipboard* clipboard, UINT32 form strcat(pDstData, ""); /* EndHTML */ - sprintf_s(num, sizeof(num), "%010lu", strlen(pDstData)); + sprintf_s(num, sizeof(num), "%010"PRIuz"", strlen(pDstData)); CopyMemory(&pDstData[43], num, 10); *pSize = (UINT32) strlen(pDstData) + 1; diff --git a/winpr/libwinpr/crt/test/CMakeLists.txt b/winpr/libwinpr/crt/test/CMakeLists.txt index 4f1f9d3fd..5f5b0132a 100644 --- a/winpr/libwinpr/crt/test/CMakeLists.txt +++ b/winpr/libwinpr/crt/test/CMakeLists.txt @@ -6,6 +6,7 @@ set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS TestTypes.c + TestFormatSpecifiers.c TestAlignment.c TestString.c TestUnicodeConversion.c) diff --git a/winpr/libwinpr/crt/test/TestFormatSpecifiers.c b/winpr/libwinpr/crt/test/TestFormatSpecifiers.c new file mode 100644 index 000000000..1e325e7d4 --- /dev/null +++ b/winpr/libwinpr/crt/test/TestFormatSpecifiers.c @@ -0,0 +1,155 @@ +#include +#include +#include + + +int TestFormatSpecifiers(int argc, char* argv[]) +{ + unsigned errors = 0; + + char fmt[4096]; + + /* size_t */ + { + size_t arg = 0xabcd; + const char *chk = "uz:43981 oz:125715 xz:abcd Xz:ABCD"; + + sprintf_s(fmt, sizeof(fmt), + "uz:%" PRIuz " oz:%" PRIoz " xz:%" PRIxz " Xz:%" PRIXz"", arg, arg, arg, arg); + + if (strcmp(fmt, chk)) + { + fprintf(stderr, "%s failed size_t test: got [%s] instead of [%s]\n", __FUNCTION__, fmt, chk); + errors ++; + } + } + + /* INT8 */ + { + INT8 arg = -16; + const char *chk = "d8:-16 x8:f0 X8:F0"; + + sprintf_s(fmt, sizeof(fmt), + "d8:%" PRId8 " x8:%" PRIx8 " X8:%" PRIX8"", arg, (UINT8) arg, (UINT8) arg); + + if (strcmp(fmt, chk)) + { + fprintf(stderr, "%s failed INT8 test: got [%s] instead of [%s]\n", __FUNCTION__, fmt, chk); + errors ++; + } + } + + /* UINT8 */ + { + UINT8 arg = 0xFE; + const char *chk = "u8:254 o8:376 x8:fe X8:FE"; + + sprintf_s(fmt, sizeof(fmt), + "u8:%" PRIu8 " o8:%" PRIo8 " x8:%" PRIx8 " X8:%" PRIX8"", arg, arg, arg, arg); + + if (strcmp(fmt, chk)) + { + fprintf(stderr, "%s failed UINT8 test: got [%s] instead of [%s]\n", __FUNCTION__, fmt, chk); + errors ++; + } + } + + /* INT16 */ + { + INT16 arg = -16; + const char *chk = "d16:-16 x16:fff0 X16:FFF0"; + + sprintf_s(fmt, sizeof(fmt), + "d16:%" PRId16 " x16:%" PRIx16 " X16:%" PRIX16"", arg, (UINT16) arg, (UINT16) arg); + + if (strcmp(fmt, chk)) + { + fprintf(stderr, "%s failed INT16 test: got [%s] instead of [%s]\n", __FUNCTION__, fmt, chk); + errors ++; + } + } + + /* UINT16 */ + { + UINT16 arg = 0xFFFE; + const char *chk = "u16:65534 o16:177776 x16:fffe X16:FFFE"; + + sprintf_s(fmt, sizeof(fmt), + "u16:%" PRIu16 " o16:%" PRIo16 " x16:%" PRIx16 " X16:%" PRIX16"", arg, arg, arg, arg); + + if (strcmp(fmt, chk)) + { + fprintf(stderr, "%s failed UINT16 test: got [%s] instead of [%s]\n", __FUNCTION__, fmt, chk); + errors ++; + } + } + + /* INT32 */ + { + INT32 arg = -16; + const char *chk = "d32:-16 x32:fffffff0 X32:FFFFFFF0"; + + sprintf_s(fmt, sizeof(fmt), + "d32:%" PRId32 " x32:%" PRIx32 " X32:%" PRIX32"", arg, (UINT32) arg, (UINT32) arg); + + if (strcmp(fmt, chk)) + { + fprintf(stderr, "%s failed INT32 test: got [%s] instead of [%s]\n", __FUNCTION__, fmt, chk); + errors ++; + } + } + + /* UINT32 */ + { + UINT32 arg = 0xFFFFFFFE; + const char *chk = "u32:4294967294 o32:37777777776 x32:fffffffe X32:FFFFFFFE"; + + sprintf_s(fmt, sizeof(fmt), + "u32:%" PRIu32 " o32:%" PRIo32 " x32:%" PRIx32 " X32:%" PRIX32"", arg, arg, arg, arg); + + if (strcmp(fmt, chk)) + { + fprintf(stderr, "%s failed UINT16 test: got [%s] instead of [%s]\n", __FUNCTION__, fmt, chk); + errors ++; + } + } + + /* INT64 */ + { + INT64 arg = -16; + const char *chk = "d64:-16 x64:fffffffffffffff0 X64:FFFFFFFFFFFFFFF0"; + + sprintf_s(fmt, sizeof(fmt), + "d64:%" PRId64 " x64:%" PRIx64 " X64:%" PRIX64"", arg, (UINT64) arg, (UINT64) arg); + + if (strcmp(fmt, chk)) + { + fprintf(stderr, "%s failed INT64 test: got [%s] instead of [%s]\n", __FUNCTION__, fmt, chk); + errors ++; + } + } + + /* UINT64 */ + { + UINT64 arg = 0xFFFFFFFFFFFFFFFE; + const char *chk = "u64:18446744073709551614 o64:1777777777777777777776 x64:fffffffffffffffe X64:FFFFFFFFFFFFFFFE"; + + sprintf_s(fmt, sizeof(fmt), + "u64:%" PRIu64 " o64:%" PRIo64 " x64:%016" PRIx64 " X64:%016" PRIX64"", arg, arg, arg, arg); + + if (strcmp(fmt, chk)) + { + fprintf(stderr, "%s failed UINT64 test: got [%s] instead of [%s]\n", __FUNCTION__, fmt, chk); + errors ++; + } + } + + if (errors) + { + fprintf(stderr, "%s produced %u errors\n", __FUNCTION__, errors); + return -1; + } + + return 0; +} + diff --git a/winpr/libwinpr/sysinfo/test/TestGetNativeSystemInfo.c b/winpr/libwinpr/sysinfo/test/TestGetNativeSystemInfo.c index 424bf01e6..49fb4f720 100644 --- a/winpr/libwinpr/sysinfo/test/TestGetNativeSystemInfo.c +++ b/winpr/libwinpr/sysinfo/test/TestGetNativeSystemInfo.c @@ -14,7 +14,7 @@ int TestGetNativeSystemInfo(int argc, char* argv[]) printf("\tdwPageSize: 0x%08"PRIX32"\n", sysinfo.dwPageSize); printf("\tlpMinimumApplicationAddress: %p\n", sysinfo.lpMinimumApplicationAddress); printf("\tlpMaximumApplicationAddress: %p\n", sysinfo.lpMaximumApplicationAddress); - printf("\tdwActiveProcessorMask: 0x%08"PRIXz"\n", sysinfo.dwActiveProcessorMask); + printf("\tdwActiveProcessorMask: %p\n", (void*) sysinfo.dwActiveProcessorMask); printf("\tdwNumberOfProcessors: %"PRIu32"\n", sysinfo.dwNumberOfProcessors); printf("\tdwProcessorType: %"PRIu32"\n", sysinfo.dwProcessorType); printf("\tdwAllocationGranularity: %"PRIu32"\n", sysinfo.dwAllocationGranularity);