29

In C++, fixed width integers are defined as optional, but I can't seems to find the recommended way to check if they are actually defined.

What would be a portable way to check if fixed width integers are available?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Rick de Water
  • 2,388
  • 3
  • 19
  • 37
  • There doesn't seem to be [feature test macro](https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros), but I suppose you can do `#if defined(INT8_MIN)` – Zereges Jan 01 '20 at 12:39
  • 2
    If the std library does not provide a feature test macro for that, then you might check if the toolchain you use provides one for it or allows you to define an own test. CMake, for example, allows you to test for certain language features by compiling a defined `cpp` file and depending on if the compilation fails or not a macro that you can define is set. – t.niese Jan 01 '20 at 12:55
  • If you prefer autoconf to cmake, it has tests predefined for them. `AC_TYPE_INT8_T` etc. – Shawn Jan 01 '20 at 13:40
  • If anyone has any tag score in [tag:stdint], IMO [tag:cstdint] should be nominated as a synonym (https://stackoverflow.com/tags/stdint/synonyms). I don't think we need separate C and C++ tags for this obscure thing; the main tag on the question is enough. – Peter Cordes Jan 02 '20 at 14:52
  • @PeterCordes The [top user in stdint has a score of 408](https://stackoverflow.com/tags/stdint/topusers). 40 makes it into the top 10. [cstdint is even worse](https://stackoverflow.com/tags/cstdint/topusers) I'm at 9 with a score of - wait for it - 14. :-/ Only Lundin and R seem to have a high enough tag score so no way to get to 4 votes. (Just now saw your comment...) – Andrew Henle Jan 30 '20 at 21:36
  • @AndrewHenle: I edited the tags on this to include both (because stdint seems more relevant than integer), so now you have some tag-score in stdint, too. – Peter Cordes Jan 30 '20 at 22:05
  • @PeterCordes Unfortunately, that didn't get me far enough. – Andrew Henle Jan 30 '20 at 22:19
  • @AndrewHenle: try again; it might have taken until overnight for tag scores to recalc. It says you have 15, and creating synonyms only requires 5 in that tag (stdint). – Peter Cordes Jan 31 '20 at 06:24
  • 1
    @PeterCordes It worked this time: https://stackoverflow.com/tags/stdint/synonyms – Andrew Henle Jan 31 '20 at 13:32

2 Answers2

21

To determine if a fixed-width integer type is provided, you can check if either of the corresponding [U]INT*_MAX or [U]INT*_MIN macros is defined.

// may be necessary for your C++ implementation
#define __STDC_LIMIT_MACROS 
#include <cstdint>

#ifdef INT32_MAX
// int32_t must be available to get here
int32_t some32bitIntVariable;
#endif

Per 7.20 Integer types <stdint.h>, paragraph 4 of the C11 standard (note the bolded parts):

For each type described herein that the implementation provides, <stdint.h> shall declare that typedef name and define the associated macros. Conversely, for each type described herein that the implementation does not provide, <stdint.h> shall not declare that typedef name nor shall it define the associated macros.

C++ inherits the C implementation via <cstdint>. See <cstdint> vs <stdint.h> for some details. Also see What do __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS mean? for details on __STDC_LIMIT_MACROS.

Thus, if int32_t is available, INT32_MAX and INT32_MIN must be #define'd. Conversely, if int32_t is not available, neither INT32_MAX nor INT32_MIN are allowed to be #define'd.

Note though, as @NicolBolas stated in another answer, it may not be necessary to actually check.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • It'll be shorter to check for `[U]INT*_C` instead of the min & max macros – phuclv Jan 02 '20 at 01:51
  • 1
    @phuclv Except that's not the same thing. e.g. `INT64_C` is defined if `int64_least_t` is available, not if `int64_t` is available. Refer to [documentation](https://en.cppreference.com/w/cpp/types/integer) – Lightness Races in Orbit Jan 02 '20 at 02:03
18

Broadly speaking... you don't.

If you need to use the fixed-sized integer types, then that means that you explicitly need those types to be of their specific sizes. That is, your code will be non-functional if you cannot get integers of those sizes. So you should just use them; if someone uses your code on a compiler that lacks said types, then your code will not compile. Which is fine, because your code wouldn't have worked if it did compile.

If you don't actually need fixed-sized integers but simply want them for some other reason, then use the int_least_* types. If the implementation can give you exactly that size, then the least_* types will have that size.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 7
    This isn't true. I've written stub passthroughs that implement operator= / etc for platforms that don't support uint8_t before. But for efficiency and debugging purposes you don't want to use the passthrough unless its actually necessary. – TLW Jan 01 '20 at 23:51
  • @TLW: "*I've written stub passthroughs that implement operator= / etc for platforms that don't support uint8_t before.*" OK, but... why? What code were you writing which needs to be certain that a byte is 8 bits (which is presumably why you were using `uint8_t`), but this code somehow needed to run on a platform where a byte isn't 8 bits (which, besides using an old C++ implementation, would be the only reason why `uint8_t` wouldn't be available)? That is, outside of backwards compatibility, why did you need to do this? – Nicol Bolas Jan 02 '20 at 23:37
  • proprietary so can't say too too much. Shared codebase that needed to support, among other things, a rather quirky hardware stack. `uint8_t` was _much_ clearer than the prior ad-hoc (and oft-broken) approach. – TLW Jan 03 '20 at 00:37
  • If you have an algorithm that is expressed in terms of e.g. 8-bit bytes, a passthrough is something that you can write once and is easy to test. Whereas fixing up every place is ad-hoc and easy to get subtly incorrect. `O(1)` versus `O(n)` effort. Same reason why people use e.g. `uint16_t`. You're asking "why not use uint32_t and cast it yourself?", to which the answer should be obvious. – TLW Jan 03 '20 at 00:41
  • 1
    @TLW: "*Same reason why people use e.g. uint16_t.*" That's not *my* reason for using `uint16_t`. My reason is that I'm communicating with a device/format/etc that is expecting to get precisely 16 bits of data formatted as a binary, unsigned integer using the endian for my machine, and if I can't get a type that is *precisely* that, then communicating effectively with it is much more difficult. My program (and the APIs that I use with it) fundamentally *cannot function* on a machine that doesn't provide that. – Nicol Bolas Jan 03 '20 at 00:48
  • ping. https://stackoverflow.com/tags/stdint/synonyms needs votes to make cstdint a synonym; you're one of a few users with any tag score in it. – Peter Cordes Jan 31 '20 at 13:44