Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declaring fixed-size integer typedef in Standard C

Is there a reliable way to declare typedefs for integer types of fixed 8,16,32, and 64 bit length in ISO Standard C?

When I say ISO Standard C, I mean that strictly:

  • ISO C89/C90, not C99.
  • No headers not defined in the ISO standard.
  • No preprocessor symbols not defined in the ISO standard.
  • No type-size assumptions not specified in the ISO standard.
  • No proprietary vendor symbols.

I see other questions similar to this in StackOverflow, but no answers yet that do not violate one of the above constraints. I'm not sure it's possible without resorting to platform symbols.

like image 914
kbluck Avatar asked Oct 09 '09 23:10

kbluck


People also ask

What are fixed width integer types?

The fixed-width integer types that <inttypes. h> provides, include signed integer types, such as int8_t, int16_t, int32_t, int64_t, and unsigned integer types, such as uint8_t, uint16_t, uint32_t, and uint64_t.

What is uint32_t in C?

uint32_t is a numeric type that guarantees 32 bits. The value is unsigned, meaning that the range of values goes from 0 to 232 - 1. This. uint32_t* ptr; declares a pointer of type uint32_t* , but the pointer is uninitialized, that is, the pointer does not point to anywhere in particular.

What is Type Def in C?

The typedef is a keyword used in C programming to provide some meaningful names to the already existing variable in the C program. It behaves similarly as we define the alias for the commands. In short, we can say that this keyword is used to redefine the name of an already existing variable.

Where is Intptr_t defined?

It's defined in /usr/include/stdint.


4 Answers

Yes you can.

The header file limits.h should be part of C90. Then I would test through preprocessor directives values of SHRT_MAX, INT_MAX, LONG_MAX, and LLONG_MAX and set typedefs accordingly.

Example:

#include <limits.h>

#if SHRT_MAX == 2147483647
typedef unsigned short int uint32_t;
#elif INT_MAX == 2147483647
typedef unsigned int uint32_t;
#elif LONG_MAX == 2147483647
typedef unsigned long uint32_t ;
#elif LLONG_MAX == 2147483647
typedef unsigned long long uint32_t;
#else
#error "Cannot find 32bit integer."
#endif
like image 134
Viliam Avatar answered Oct 17 '22 19:10

Viliam


Strictly speaking, ISO 9899:1999 superceded ISO 9899:1990 so is the only current ISO standard C language specification.

As exact width typedef names for integer types were only introduced into the standard in the 1999 version, what you want is not possible using only the 1990 version of the standard.

like image 38
CB Bailey Avatar answered Oct 17 '22 19:10

CB Bailey


There is none. There is a reliable way to declare individual integer variables up to 32 bits in size, however, if you're willing to live with some restrictions. Just use long bitfields (the latter is guaranteed to be at least 32-bit wide, and you're allowed to use up to as many bits in a bitfields as would fit in the variable if bitfield declarator was omitted). So:

struct {
   unsigned long foo : 32; 
} bar;

Obviously, you get all the limitations that come with that, such as inability to have pointers to such variables. The only thing this really buys you is guaranteed wraparound at the specified boundary on over/underflow, and even then only for unsigned types, since overflow is undefined for signed.

Aside from that, there's no portable way to do this in pure C90. Among other things, a conformant C90 implementation need not even have a 8-bit integer, for example - it would be entirely legal to have a platform in which sizeof(char) == sizeof(short) == sizeof(int) == 1 and CHAR_BIT == 16 (i.e. it has a 16-bit machine word, and cannot address individual bytes). I've heard that such platforms do in fact exist in practice in form of some DSPs.

like image 3
Pavel Minaev Avatar answered Oct 17 '22 18:10

Pavel Minaev


A danger with such approaches when using modern compilers is that it has become fashionable for compilers to assume that a pointer of one integer type will not be used to access values of another, even when both types have the same size and representation. If two types have the same size and representation, and two parts of the same program each choose one of them, applying link-time optimizations to programs that share pointers to such data could result in improper behavior. For some implementations on many systems, there will be at least one size of integer for which it will be impossible to declare a pointer which can be safely used to access all integer values of that size; e.g. on systems where both long and long long are 64 bits, there will be no way to declare a pointer which can be used reliably to access data of either type interchangeably.

like image 1
supercat Avatar answered Oct 17 '22 17:10

supercat