6

I just started working on a big project which is supposed to be platform independent, but it actually uses types which are implementation defined such as char.

This had already caused some problems, since for some devices char is by default signed while for others unsigned.

I would like to find a solution in order to avoid the use of implementation defined types in code that must be platform independent.

  1. What would be the best solution? Re-defining all the char variables as unsigned char (or signed char), using compiler parameters (ex: -funsigned-char), typedefs, or others?
  2. Are there other types for which the standard does not define if they are either signed or unsigned?
Nick
  • 9,515
  • 17
  • 75
  • 175
  • 1
    https://en.wikibooks.org/wiki/C_Programming/inttypes.h – Iłya Bursov Aug 25 '17 at 16:28
  • The signedness of `char` is not platform, but compiler defined. So any of listed in `1` will do. But I would go with explicit type declaration. 2) No (for the standard built-in types). – Eugene Sh. Aug 25 '17 at 16:28
  • 2
    @EugeneSh. "Platform" usually includes compiler too :) – P.P Aug 25 '17 at 16:29
  • @P.P. Yes, what I meant it is exclusively compiler-defined. – Eugene Sh. Aug 25 '17 at 16:30
  • You could use the types `int8_t` etc to be found in `stdint.h`. Not all compilers support that - such as a previous older version of MSVC, in that case I provided my own. AFAIK `char` is the only type which may be `unsigned` except for those which are always unsigned such as `size_t`. – Weather Vane Aug 25 '17 at 16:31
  • @IlyaBursov But note that fixed-width integer types such as `int32_t` are in fact *optional*. – Andrew Henle Aug 25 '17 at 16:34
  • @AndrewHenle hm, can you elaborate? i was under impression that c99 requires it – Iłya Bursov Aug 25 '17 at 16:37
  • 2
    @IlyaBursov *i was under impression that c99 requires it* Not always. Per **7.20.1.1 Exact-width integer types**, paragraph 3 of [the C standard](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf): "These types are optional." But, it's followed by "However, if an implementation provides integer types with widths of 8, 16, 32, or 64 bits, no padding bits, and (for the signed types) that have a two’s complement representation, it shall define the corresponding typedef names." So, common systems *are* required to have the fixed-width integer types. – Andrew Henle Aug 25 '17 at 16:46
  • After taking into account [@Felix Palmen](https://stackoverflow.com/a/45885918/2410359) fine answer, point to add: "a big project which is supposed to be platform independent", --> avoid lots of types. Restrict types to a minimal set. E.g. `long long` not needed, use `intmax_t`. `short` rarely needed. – chux - Reinstate Monica Aug 25 '17 at 17:38

3 Answers3

5

In theory, the answer is very simple:

Always use types for the purpose they are intended for. E.g. you want implementation-defined types for something like the size of an array because on different platforms, the upper bound of such a size will be different. Similar for pointers. For the need of fixed-size types, C already provides appropriate typedefs in stdint.h.

Here's an incomplete "what-to-use" list:

  • Use (unsigned) int for any integer that doesn't need to have a fixed size and will never exceed the range of 16 bits
  • Use char for characters, int and casts to unsigned char when dealing with library functions that store characters in an int.
  • Use size_t for anything related to the size of objects, e.g. array indices
  • Use uintptr_t whenever you need to store the value of a pointer in an integer
  • Use intX_t/uintX_t (with X being the number of bits) for any integer where you need a fixed number of bits that shouldn't change depending on the target platform.
  • If it doesn't matter whether the size of the type is actually larger, use int_leastX_t/uint_leastX_t instead. An implementation that can't address an octet wouldn't provide e.g. uint8_t, but it would provide uint_least8_t with more bits.
  • *but it would (probably) provide `uint_least8_t` with more bits* But `uint_least8_t` is required by the C standard. If the platform isn't standard-compliant, actual portability without using platform-specific `typedef`'s is quite possibly impossible. – Andrew Henle Aug 25 '17 at 16:49
  • @AndrewHenle well, I'll change that to something more precise ... forget it, I'll just remove the "probably" -- you're correct, discussing implementations not conforming to at least C99 doesn't make much sense here –  Aug 25 '17 at 16:50
1

the classic way to do it is to use your own typedefed types and have your make/autoconf etc detect the platform characteristics and set up the typdefs for you.

pm100
  • 32,399
  • 19
  • 69
  • 124
  • This is the old-fashioned way of doing it. But maintaining your own typedefs is a big, unnecessary nuisance. Use the standard types in `` instead: `int8_t`, `uint16_t`, etc. – Steve Summit Aug 25 '17 at 18:42
  • i was going to say that, but that depends on what compilers you have and whether or not they support those standards (I know all modern ones should). Plus there may be types he needs that are not covered – pm100 Aug 25 '17 at 20:12
0

There are two schools of thought on this:

  1. Never use the "plain" types like int and char, since you can never know how big they are. Always use fixed-size types, such as the ones defined in <stdint.h>.
  2. Use the "plain" types like int and char whenever you can, since they should always match the native types on your machine. Understand what's guaranteed and not guaranteed about them, so that you can choose the appropriate one -- that is, sometimes you'll want long int, or unsigned int, or size_t, or something else. On those (hopefully rare) occasions when you absolutely need an exact-sized type, use the ones defined in <stdint.h>.

It turns out this is an age-old question, which has been argued forever, with no one agreed-upon answer.

Steve Summit
  • 29,350
  • 5
  • 43
  • 68