7

I know this has been questioned many times on SO, but my problem is specific to ANSI C (C89).

In C99 there are the sub-specifiers z and t, which are not supported in ANSI C.

What about using the p specifier?

32
  • 4
    AFAIK ANSI autmatically adopts the ISO standard, so you should be able to use the same. In case you mean C89/90 ()which is unambiguous): there is no way. Note that C99 is not standard C; that would be C11. Commented May 28, 2017 at 18:46
  • 5
    @levengli: Please refrain from stating such nonsense! size_t cannot be int and ptrdiff_t will not on systems where int is insufficient, like most 64 bit architectures and some 8/16 bit architectures Commented May 28, 2017 at 18:47
  • 3
    @DietrichEpp Yeah, but every C standard explicitly invalidates its predecessor, so "the C standard" always refers to the latest one. Commented May 28, 2017 at 18:51
  • 3
    @Olaf What is the point of arguing about this ? The OP explicitly asks about C89. The OP knows more about his environment than what you do, so if he asks about C89, simply provide an answer for that, or don't. Commented May 28, 2017 at 18:54
  • 5
    @Olaf: It's true that the 2011 ISO C standard is the one currently recognized by ANSI, the American National Standards Institute. But you should be aware that practically nobody refers to C11 as "ANSI C". Even without the clarifying "(C89)", it was perfectly clear that the OP was asking about C89/C90. The OP's error (such as it was) was in referring to that language as "ANSI C". If you want to point that out, that's fine, but pretending that the OP really wanted to ask about a later standard is not helpful. Commented May 28, 2017 at 20:16

1 Answer 1

14

size_t is an implementation-defined unsigned integer type. ptrdiff_t is an implementation-defined signed integer type.

In C89/C90 (commonly, but strictly speaking incorrectly, referred to as "ANSI C"), there are no special format specifiers for these types. But the widest integer types are long int and unsigned long int, which of course do have their own format specifiers.

To print a size_t value, cast it to unsigned long and use "%lu".

To print a ptrdiff_t value, cast it to long and use "%ld".

Note that if your code is then compiled with a C99 or C11 compiler, it's possible that size_t and/or ptrdiff_t could be wider than long, and the code could fail. (As I recall the 64-bit Windows interface has 32-bit long, so that could be an issue in practice.)

In C99 and later, just use %zu for size_t and %td for ptrdiff_t. If you want your code to be really portable, consider using #if to test the value of __STDC_VERSION__.

You could also run into problems if you have a compiler that only partially conforms to C99 or C11. You might have a compiler that doesn't fully support C99, but that does provide long long. But for the purpose of printing a size_t value, that's only going to be an issue if the value you're printing actually exceeds ULONG_MAX, which is at least 232-1. For a ptrdiff_t value, converting to long is OK as long as it doesn't exceed LONG_MAX, which is at least 231-1.

Finally, if you happen to know that the values you're printing aren't too big, you can get away with casting to int and using %d. I recommend casting to unsigned long or long, but int is OK for quick-and-dirty code.

What about using the p specifier?

No, %p is only for pointers of type void*, and in any case the output format is implementation-defined (it's commonly hex, but I've seen other representations).

Sign up to request clarification or add additional context in comments.

16 Comments

C89 says "There are four signed integer types, designated as signed char, short int, int, and long int". The problem with this provision is that literally no existing major implementation follows it to the letter. size_t may well be defined to be long long unsigned int or __uint64 or some such. Who you gonna call?
@n.m.: A compiler that supports long long unsigned int and doesn't issue at least a warning message for any use of it is not a conforming C89/C90 compiler. long long unsigned int is a syntax error in C89/C90.
"is not a conforming C89/C90 compiler" this is a very correct observation, and also a very useless one. Here's your MSVC, go write some code. Not compliant? Who cares?
@BiteBytes: %p requires an argument of type void*. Pointers are not integers, and they cannot safely be used interchangeably. Using %p with an argument of any type other than void* has undefined behavior. (It might also be valid to use %p with char*, unsigned char*, or signed char*, but I'd cast to void* anyway.)
@n.m.: I'd rather cast size_t to unsigned long and print with %u. That's guaranteed to print the correct result, as long as the value being printed doesn't exceed 2^32-1.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.