diff options
Diffstat (limited to 'docs/PrintFormatSpecifiers.md')
-rw-r--r-- | docs/PrintFormatSpecifiers.md | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/docs/PrintFormatSpecifiers.md b/docs/PrintFormatSpecifiers.md new file mode 100644 index 0000000..1182f84 --- /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) |