- POSIX defines that in_port_t is equal to uint16_t, so for that type there's no problem at all ;)
- Don't use printf/scanf for this, roll your own
- Refuse to print/read uid_t that are outside intmax_t range
- Use an autoconf test
- POSIX defines that in_port_t is equal to uint16_t, so for that type there's no problem at all ;)
- Don't use printf/scanf for this, roll your own
- Refuse to print/read uid_t that are outside intmax_t range
- Use an autoconf test
Until then I guess I’ll have to do something like
#if sizeof(pid_t) > sizeof(uintmax_t)
#error Nope
#endif
…repeated for all the types I need to parse and/or print.Also this doesn't just apply "in the future" -- integer types larger than intmax_t already exist, C23 just updates the standard to match reality.
#if SIZEOF_PID_T > SIZEOF_UINTMAX_T
...
#endif
Where you detect these sizes from the toolchain and deposit them as #define constants in some "config.h" header.There are ways to detect sizes by compiling a source file to an object file, and then analyzing the object file (no execution), so things work under cross-compiling.
I've used a number of tricks over the years, and settled on this one:
https://www.kylheku.com/cgit/txr/tree/configure?h=txr-278#n1...
The basic idea is that we can take a value like sizeof(long), which is a constant, and using nothing but constant arithmetic, we can convert it to the characters " 8". These characters can be placed into a character array where they are delimited by some prefix that we can look for in the compiled object file with some common utilities.
This is quite durable in the sense that it can be reasonably expected to work through a wide variety of object formats.
In that test program, I have a structure with some character arrays. The larger character arrays hold the informative prefixes. The two-byte arrays hold decimal digits for sizes. Two digits go up to 99 bytes so we are safe for a number of years.
The DEC macro calculates the ASCII decimal value of its argument, expanding to a two-byte initializer for a character array:
#define D(N, Z) ((N) ? (N) + '0' : Z)
#define UD(S) D((S) / 10, ' ')
#define LD(S) D((S) % 10, '0')
#define DEC(S) { UD(S), LD(S) }
E.g. DEC(42) -> /* the equivalent of */ { '4', '2' }
But actually DEC(42) -> { UD(42), LD(42) }
-> { D((42) / 10, ' '), D((42) % 10, '0') }
-> { ((42) / 10) ? ((42 / 10)) + '0' : ' ',
((42) % 10) ? ((42 % 10)) + '0' : '0' }
The space instead of a leading zero is so that if we pull this into shell arithmetic, it isn't confused for an octal number.