I tried to obtain the number of characters read as a size_t, using this program:¹
#include <stdio.h>
int main(void)
{
size_t i;
sscanf("abc", "%*s%zn", &i);
printf("%zu", i);
}
GCC 12 warns about this:
scanf.c: In function ‘main’:
scanf.c:7:25: warning: format ‘%zn’ expects argument of type ‘signed size_t *’, but argument 3 has type ‘size_t *’ {aka ‘long unsigned int *’} [-Wformat=]
7 | sscanf("abc", "%*s%zn", &i);
| ~~^ ~~
| | |
| | size_t * {aka long unsigned int *}
| long int *
| %ln
And it's correct² do do so; in the C17 draft standard, page 234, we read (my emphasis)
No input is consumed. The corresponding argument shall be a pointer to signed integer into which is to be written the number of characters read from the input stream so far by this call to the
fscanffunction.
Earlier standards contain similar wording.
So how do I (portably) create a signed equivalent of size_t for this conversion?
In C++, I could use std::make_signed_t<std::size_t>, but that's obviously not an option for C code. Without that, it seems that %zn conversion is unusable in C.
¹ The real-world case from which this arises came from reviewing Simple photomosaic generator, where we wanted a more general form of strto(), and so need %n to determine the end of conversion. I know we can use plain int for all here, but wanted to check the expected behaviour before reporting as a bug.
² Other than calling the required type signed size_t *, which is obviously not a valid C type name.
You are out of luck. As of C17
And
size_tis an unsigned type.Yet C never details how to make the corresponding signed integer type.
There is no specified signed type corresponding to
size_tin standard C.Alternatives:
Live with
"%n", &int_objectand thensize_t i = (unsigned) int_object;. (Cast important)Use
"%jn", &intmax_t_objectand thensize_t i = (size_t) intmax_t_object;.If pressed to typedef a
signed_size_t, the following should portably work, but you are on your own.About non-standard
ssize_tssize_tis not a certain match for the corresponding signed integer type.Even The Open Group Base Specifications Issue 7, 2018 edition has:
Similar question How to use "zd" specifier with
printf()?.