4

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?

Bite Bytes
  • 1,455
  • 8
  • 24
  • By the way, instead of down voting, you can share a link to the answer (if you can) – Bite Bytes May 28 '17 at 18:46
  • 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. – too honest for this site May 28 '17 at 18:46
  • Simply use %d. They are, asst the bottom of things, typedef to int – levengli May 28 '17 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 – too honest for this site May 28 '17 at 18:47
  • @levengli %lu is correcter, but not correct – Bite Bytes May 28 '17 at 18:48
  • @Olaf: Just because a standard has been superseded doesn't mean it isn't still a standard. – Dietrich Epp May 28 '17 at 18:50
  • 3
    @DietrichEpp Yeah, but every C standard explicitly invalidates its predecessor, so "*the C standard*" always refers to the latest one. – melpomene May 28 '17 at 18:51
  • 1
    @DietrichEpp: The second release of the C standard (aka C99) has explicitly been **canceled**. Last time I check the meaning of this word it implied the second release is **not** standard. You might want to read the foreword of ISO9899:2011. – too honest for this site May 28 '17 at 18:51
  • What is a `sub-specifier`? – Sourav Ghosh May 28 '17 at 18:53
  • 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. – nos May 28 '17 at 18:54
  • 1
    @SouravGhosh: I'd assume OP means the _length modifier_. – too honest for this site May 28 '17 at 18:54
  • @nos: What do you mean? OP only mentions ANSI C which refers to the US institution. If he means C89(90 (they are bascially the same), he should add the appropriate tag; after all that's what tags are for. (maybe you check the edit-history and the timestamps before commenting) – too honest for this site May 28 '17 at 18:55
  • @nos At the time of Olaf's comment, the question just said "ANSI C". OP edited the question to add "C89" afterwards. – melpomene May 28 '17 at 18:56
  • "In 1990, the ANSI C standard (with formatting changes) was adopted by the International Organization for Standardization (ISO) as ISO/IEC 9899:1990, which is sometimes called C90. Therefore, the terms "C89" and "C90" refer to the same programming language." wikipedia – Bite Bytes May 28 '17 at 18:58
  • 1
    @BiteBytes Yes, and later ISO/IEC 9899:1999 (C99) was adopted as ANSI C, and then C11 was adopted as ANSI C. – melpomene May 28 '17 at 18:59
  • @melpomene ok thank's. – Bite Bytes May 28 '17 at 19:02
  • 1
    @Olaf: A withdrawn standard doesn't stop being a standard, it stops being the current standard. It seems that the question may have been edited within the edit window where revisions don't show, so if the question previously said "standard C" or something I can't speak to that. – Dietrich Epp May 28 '17 at 19:05
  • 3
    You can always print it with `lu`, **with the value cast to `(unsigned long)`** - the actual value might be displayed modulo something big, but that's about the best you can get with such an obsolete standard. – Antti Haapala -- Слава Україні May 28 '17 at 19:13
  • 1
    The alternative is to write your own code to convert the value to decimal and write it on the given stream, it's quite easy, although of course it's not as convenient as a builtin `printf` specifier. – Matteo Italia May 28 '17 at 19:58
  • @DietrichEpp: That's why I use the same word the standard uses "canceled". I'm very confident it is not the same as "withdrawn". But feel free to provide an autoritative reference proving me wrong; I always like to learn something new. And the history shows very well the original version. – too honest for this site May 28 '17 at 20:06
  • If there had been a way in pre-C99, it would not have had to be added to the standard, would it? C is not very famous for providing redundant features. Supporting @AnttiHaapala: Don't use such old versions; get a modern toolchain (gcc or clang are a good pick, including a lot of embedded systems) and write modern C. C90 has other problems and pitfalls. Not all are addressed by the current standard, but modern compilers will warn about a lot of them (which implies: **always enable all recommended warnings**). – too honest for this site May 28 '17 at 20:07
  • 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. – Keith Thompson May 28 '17 at 20:16
  • @KeithThompson: It is really funny how people only concentrate on the first part of my comment and completely ignore the much more relevant middle part which give the correct information. – too honest for this site May 28 '17 at 21:03
  • @BiteBytes: Out of curiosity: what keeps you from using modern C (which started with C99)? Just blink if there is someone standing behind you with a gun. – too honest for this site May 28 '17 at 22:07
  • @Olaf because it's the most portable version of C, and I wish I can restrict my programs to C89, and not using all the extra features that come with every compiler, witch make the program even less portable. The irony is that I started programming in 2005 using VB and C++ then I learned COM/OLE/AcitveX (yeah the evil from the old world), and I was fascinated by, then I learned C# and JAVA and Assembly Language after that, and I came up with the conclusion: "don't use what you don't need". So I started to clean the mess. – Bite Bytes May 28 '17 at 22:25
  • So to summarise: you stick with a 28 year old language instead of using an 18 year old or the already 6 year old current version. You willfully ignore the advances to enhance code quality. To be clear: this is not about "features", but to write good code! Sorry,but that makes me shiver. – too honest for this site May 28 '17 at 22:29
  • @Olaf the problem is not with the modern language, and the extra features it has, the problem is you're not going to find a compiler that support all those features in every platform you intend to target. – Bite Bytes May 28 '17 at 22:32
  • Wasn't part of the point of C99 to be more portable, e.g., with fixed-width integer types? – ad absurdum May 28 '17 at 22:34
  • 1
    @DavidBowling: And to fixe such flaws like missing conversion type specifiers for standard types. Yes. That's exactly the point. – too honest for this site May 28 '17 at 23:59
  • I wonder for which hosted environments you do **not** find a modern C compiler. Anyway, good luck for your job. – too honest for this site May 29 '17 at 00:00
  • @Olaf Just in case, you never know, thank's for all. – Bite Bytes May 29 '17 at 01:27
  • Closely related to [How to use `printf()` to display `off_t`, `nlink_t`, `size_t` and other special types?](https://stackoverflow.com/questions/1401526) – Jonathan Leffler May 29 '17 at 02:13

1 Answers1

12

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).

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 1
    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. could be an AI May 28 '17 at 20:39
  • 1
    @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. – Keith Thompson May 28 '17 at 20:40
  • "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? – n. m. could be an AI May 28 '17 at 20:43
  • @n.m.: I've updated my answer to cover that possibility. Using the C89-conforming solution, it's only a problem if the value being printed exceeds `ULONG_MAX` or `LONG_MAX`. – Keith Thompson May 28 '17 at 20:44
  • I have tested gcc and clang in strict c90 mode, they both warn about `long long` but not about `uint64`, which is I suppose the expected behaviour. This is less relevant on Unixes where sizeof(long) is normally 8 in 64 bit mode, but I hear Windows builds like mingw use sizeof(long)==4. I wonder how is size_t defined there. – n. m. could be an AI May 28 '17 at 20:54
  • I would expect an undeclared identifier error for `int64`; I presume you meant `int64_t`. To refer to `int64_t` in C90 mode, you'd have to have `#include `, which includes a non-standard header (non-standard headers are permitted, so there's nothing to warn about there). And if `long` is 64 bits, then the non-standard `` and refer to `uint64_t` with `gcc -std=c90 -pedantic -m32` (which forces 32-bit `long`), with no diagnostic. ... – Keith Thompson May 28 '17 at 21:03
  • ... That *might* be a C90 conformance issue. n further investigation `` has `typedef long long int int64_t;`, which should be a C90 syntax error, but the fact that it's a non-standard header might be relevant. – Keith Thompson May 28 '17 at 21:04
  • "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." There is no requirement to warn about wrong variadic arguments passed to `printf`, etc. Unless I missed something this never has been a requirement until, and including the (current) standard. – too honest for this site May 28 '17 at 21:05
  • @Olaf: What I meant is that `long long int` is a syntax error in C89/C90. A conforming C89/C90 compiler must issue a diagnostic if it sees that token sequence. (gcc's failure to do so when it appears in the non-C90-standard `` header seems questionable.) – Keith Thompson May 28 '17 at 21:08
  • As a sidenote: Support for the C99 modifiers is a matter of the standard library. Compilers like gcc don't provide the library, but rely on the existing one for the system. If you test at compile-time, there might be a problem when the code is run on a different environment. – too honest for this site May 28 '17 at 21:09
  • Ok, that would be a possiblity. But as you know a compiler can provide more types than the standard ones and it is used exesively (actually `long long int` etc. were introduced to get some ground to incompatible wider types - I think I read something about the "battle" for the correct name), there is no guarantee it will be available on a different machine, too. However one sees it, it is patchwork. Exactly this wa the reason introducing the new specifiers (although one could argue the way of `inttypes.h`/`stdint.h` would have been the more portable) – too honest for this site May 28 '17 at 21:13
  • Sorry to interrupt you guys, to ask again about the specifier `p`, I thought to my self, this one can print the address, which I assume is the longest integer in the machine (I guess), so why not using it to print `size_t`, where is the problem exactly? could `sizeof(size_t)` be greater than `sizeof(void*)`? – Bite Bytes May 28 '17 at 21:17
  • 3
    @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.) – Keith Thompson May 28 '17 at 21:19
  • You can cast `size_t` to `void*` and print that with `%p`. There is no guarantee in the standard that it is going to print the correct result, but in practice this should work on the vast majority of compilers (I cannot think of one which would not do the right thing). – n. m. could be an AI May 28 '17 at 21:33
  • 1
    @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. – Keith Thompson May 28 '17 at 21:39
  • 3½ years later: Oops. I should have said `%lu` for `unsigned long`, not `%u`. Of course just use `%zu` for `size_t` if you can rely on having C99 or later. – Keith Thompson Oct 07 '20 at 18:25