Over the last 10 years, the traditional C/C++ data types have been
displaced by a hodgepodge of new data types that promise portability
and generate useful (and not so useful) warnings, for example:
for (int i=0; i<array_of_10_elements.size(); i++)
is now a warning with a promise of crash (in theory, even if "int" is 64 bit).
"int" and "long" are dead, welcome "size_t", "off64_t" & co.
What to do, what to do? This is what I figured out:
1) for data returned from hardware: use uint16_t, uint32_t, uint64_t, uint128_t (u16, u32, u64 in
the Linux kernel), they have well defined width to match hardware (FPGA, AXI, VME, etc) data
widths.
2) for variables used with strlen(), array.size(), etc: use size_t, a data type wide enough to
store the biggest data size possible on this hardware (32-bit on 32-bit machines, 64-bit on 64-bit
machines). use with printf("%zu").
3) for return values of read() and write() syscalls: use ssize_t and observe an inconsistency,
read() and write() syscalls take size_t (32/64 bits), return ssize_t (31/63 bits) and the error
check code cannot be written without having to defeat the C/C++ type system (a cast to size_t):
size_t s = 100;
void* ptr = malloc(s);
ssize_t rd = read(fd, ptr, s);
if (rd < 0) { syscall error }
else if ((size_t)rd != s) { short read, important for TCP sockets }
else { good read }
use ssize_t with printf("%zd")
4) file access uses off64_t with lseek64() and ftruncate64(), this is a signed type (to avoid the
cast in the error handling code) with max file size 2^63 (at $/GB, storage for a file of max size
costs $$$$$, you cannot have enough money to afford one). use with printf("%jd", (intmax_t)v).
intmax_t by definition is big enough for all off64_t values, "%jd" is the corresponding printf()
format.
5) there is no inconsistency between 32-bit size_t and 64-bit off64_t, on 32-bit systems you can
only read files in small chunks, but you can lseek64() to any place in the file.
BTW, 64-bit time_t has arrived with Ubuntu LTS 24.04, I will write about this some other time. |