Skip to content

Commit

Permalink
ctest for int format specifiers and usage doc
Browse files Browse the repository at this point in the history
  • Loading branch information
nfedera committed Dec 16, 2016
1 parent f71b6b4 commit ab0408a
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 7 deletions.
3 changes: 1 addition & 2 deletions channels/serial/client/serial_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
131 changes: 131 additions & 0 deletions docs/PrintFormatSpecifiers.md
Original file line number Diff line number Diff line change
@@ -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)
8 changes: 4 additions & 4 deletions winpr/libwinpr/clipboard/synthetic.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ static void* clipboard_synthesize_html_format(wClipboard* clipboard, UINT32 form
body = strstr(pSrcData, "<BODY");

/* StartHTML */
sprintf_s(num, sizeof(num), "%010lu", strlen(pDstData));
sprintf_s(num, sizeof(num), "%010"PRIuz"", strlen(pDstData));
CopyMemory(&pDstData[23], num, 10);

if (!body)
Expand All @@ -391,20 +391,20 @@ static void* clipboard_synthesize_html_format(wClipboard* clipboard, UINT32 form
strcat(pDstData, "<!--StartFragment-->");

/* 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, "<!--EndFragment-->");

if (!body)
strcat(pDstData, "</BODY></HTML>");

/* 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;
Expand Down
1 change: 1 addition & 0 deletions winpr/libwinpr/crt/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
155 changes: 155 additions & 0 deletions winpr/libwinpr/crt/test/TestFormatSpecifiers.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#include <stdio.h>
#include <winpr/wtypes.h>
#include <winpr/string.h>


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;
}

2 changes: 1 addition & 1 deletion winpr/libwinpr/sysinfo/test/TestGetNativeSystemInfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit ab0408a

Please sign in to comment.