10

I'm writing a program involving network I/O, so send and recv are used, which are POSIX functions. They return a ssize_t, which is POSIX-specific too.
The wrappers look like this ATM:

ssize_t sock_send(int sock, const void* msg, size_t len) {
    return send(sock, msg, len, 0);
}

Even though I'm heavily depending on POSIX in my current implementation, I want to make the interface stick closely to the standard because I am planning on writing a Windows implementation later, where POSIX isn't necessarily available (dammit, Windows!).

What would be a good substitution for ssize_t as specified by the C11 standard? Perhaps ptrdiff_t?
Or how should I approach this issue otherwise?

cadaniluk
  • 15,027
  • 2
  • 39
  • 67

1 Answers1

11

If the type ssize_t is not defined, you can just define it yourself. It is supposed to be a signed type with the same size as size_t. Technically, the type ptrdiff_t should not be smaller than size_t, but it could be larger to accommodate for the larger range.

Here is a portable way to define it:

#include <limits.h>
#include <stddef.h>
#include <inttypes.h>
#include <stdint.h>

#if SIZE_MAX == UINT_MAX
typedef int ssize_t;        /* common 32 bit case */
#define SSIZE_MIN  INT_MIN
#define SSIZE_MAX  INT_MAX
#elif SIZE_MAX == ULONG_MAX
typedef long ssize_t;       /* linux 64 bits */
#define SSIZE_MIN  LONG_MIN
#define SSIZE_MAX  LONG_MAX
#elif SIZE_MAX == ULLONG_MAX
typedef long long ssize_t;  /* windows 64 bits */
#define SSIZE_MIN  LLONG_MIN
#define SSIZE_MAX  LLONG_MAX
#elif SIZE_MAX == USHRT_MAX
typedef short ssize_t;      /* is this even possible? */
#define SSIZE_MIN  SHRT_MIN
#define SSIZE_MAX  SHRT_MAX
#elif SIZE_MAX == UINTMAX_MAX
typedef uintmax_t ssize_t;  /* last resort, chux suggestion */
#define SSIZE_MIN  INTMAX_MIN
#define SSIZE_MAX  INTMAX_MAX
#else
#error platform has exotic SIZE_MAX
#endif
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 3
    I know at least one platform where this fails: On MSP430X microcontrollers, some toolchains (notably recent versions of the gcc toolchain) use an `uint20_t` for `size_t` and an `int20_t` for `ssize_t`. – fuz Jan 03 '16 at 19:38
  • @FUZxxl: how many bits for the standard types `char`, `short`, `int`, `long` and `long long`? – chqrlie Jan 03 '16 at 20:06
  • @chrqlie 8, 16, 16, 32, 64. `uintptr_t`, `ptrdiff_t`, `intptr_t`, `size_t`, and `ssize_t` all have 20 bit though. – fuz Jan 03 '16 at 20:06
  • @FUZxxl: then indeed the type `ssize_t` cannot be inferred from `SIZE_MAX` and must be had coded. – chqrlie Jan 03 '16 at 20:19
  • When you wrote "ptrdiff_t should not be smaller than size_t" don't you mean "ptrdiff_t should not be smaller than ssize_t" ? – j b Oct 05 '18 at 08:49
  • I mean this: `ptrdiff_t` is a signed type, so you could define `ssize_t` as an alias to `ptrdiff_t` but on some architectures you might get a type larger than `size_t`, that is `sizeof(ptrdiff_t) > sizeof(size_t)`, which is not intended. The problem is you cannot test if `sizeof(ptrdiff_t) == sizeof(size_t)` at the preprocessor level, so you must test numeric values as posted in the answer. – chqrlie Oct 06 '18 at 10:41
  • why use architectures where the number of the native integer bits are not a power of 2? actually, why did they do it? to abuse developers? – neo5003 Jun 08 '19 at 11:39
  • The "is this even possible?" is possible with 16-bit systems that have 32-bit int. – S.S. Anne Apr 22 '20 at 21:48
  • @S.S.Anne: I guess it is possible in theory, but I have never come across an architecture with this combination. Have you? – chqrlie Apr 22 '20 at 22:15
  • I might have, I'm not sure. – S.S. Anne Apr 22 '20 at 22:16
  • "It is supposed to be a signed type with the same size as size_t" seems common, yet I find no spec support for that. [The implementation shall support ... environments in which the widths of ... ssize_t, ... are no greater than the width of type long](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_types.h.html) maybe useful. – chux - Reinstate Monica Sep 12 '20 at 20:30
  • 2
    @fuz `uint20_t` and 8-bit `char` looks non-compliant as `uintN_t` and `char` should not have padding and bit width of 20 is not a multiple of bit width of 8. Hmmm. – chux - Reinstate Monica Sep 12 '20 at 20:39
  • chqrlie, The `#if SIZE_MAX == UINT_MAX` approach is a reasonable one - UV. Within that _if_ tree, useful to include defines for `SSIZE_MIN` and `SSIZE_MAX`. For pedantic future growth,I'd include `#elif SIZE_MAX == UINTMAX_MAX` – chux - Reinstate Monica Sep 12 '20 at 20:45
  • @chux-ReinstateMonica: good suggestions, answer amended. – chqrlie Sep 12 '20 at 21:08
  • 1
    @chux-ReinstateMonica True, that! They should have called it `__uint20_t` or something similar. – Ian Abbott Jul 08 '21 at 15:46