I'm looking at stdint.h and given that it has uint16_t and uint_fast16_t, what is the use for uint_least16_t what might you want that couldn't be done equally well with one of the other two?
Say you're working on a compiler with:
unsigned char is 8 bits
unsigned short is 32 bits
unsigned int is 64 bits
And unsigned int is the 'fastest'. On that platform:
uint16_t would not be available
uint_least16_t would be a 32 bit value
uint_fast16_t would be a 64 bit value
A bit arcane, but that's what it's for.
How useful they are is another story - I see the exact size variants all the time. That's what people want. The 'least' and 'fast' versions I've seen used pretty close to never (it's possible that it was only in example code - I'm really not sure).
Ah, the link Patrick posted includes this "The typedef name uint_leastN_t designates an unsigned integer type with a width of at least N, such that no unsigned integer type with lesser size has at least the specified width."
So my current understanding is:
uint_least16_t the smallest thing that is capable of holding a uint16
uint_fast16_t the fastest thing that is capable of holding a uint16
uint16_t exactly a uint16, unfortunately may not be available on all platforms, on any platform where is is available uint_least16_t will refer to it. So if it were guaranteed to exist on all platforms we wouldn't need uint_least16_t at all.
It's part of the c standard. It doesn't need a good use case. :P
See this page and look for the section titled "Minimum-width integer types".
Related
I notice that modern C and C++ code seems to use size_t instead of int/unsigned int pretty much everywhere - from parameters for C string functions to the STL. I am curious as to the reason for this and the benefits it brings.
The size_t type is the unsigned integer type that is the result of the sizeof operator (and the offsetof operator), so it is guaranteed to be big enough to contain the size of the biggest object your system can handle (e.g., a static array of 8Gb).
The size_t type may be bigger than, equal to, or smaller than an unsigned int, and your compiler might make assumptions about it for optimization.
You may find more precise information in the C99 standard, section 7.17, a draft of which is available on the Internet in pdf format, or in the C11 standard, section 7.19, also available as a pdf draft.
Classic C (the early dialect of C described by Brian Kernighan and Dennis Ritchie in The C Programming Language, Prentice-Hall, 1978) didn't provide size_t. The C standards committee introduced size_t to eliminate a portability problem
Explained in detail at embedded.com (with a very good example)
In short, size_t is never negative, and it maximizes performance because it's typedef'd to be the unsigned integer type that's big enough -- but not too big -- to represent the size of the largest possible object on the target platform.
Sizes should never be negative, and indeed size_t is an unsigned type. Also, because size_t is unsigned, you can store numbers that are roughly twice as big as in the corresponding signed type, because we can use the sign bit to represent magnitude, like all the other bits in the unsigned integer. When we gain one more bit, we are multiplying the range of numbers we can represents by a factor of about two.
So, you ask, why not just use an unsigned int? It may not be able to hold big enough numbers. In an implementation where unsigned int is 32 bits, the biggest number it can represent is 4294967295. Some processors, such as the IP16L32, can copy objects larger than 4294967295 bytes.
So, you ask, why not use an unsigned long int? It exacts a performance toll on some platforms. Standard C requires that a long occupy at least 32 bits. An IP16L32 platform implements each 32-bit long as a pair of 16-bit words. Almost all 32-bit operators on these platforms require two instructions, if not more, because they work with the 32 bits in two 16-bit chunks. For example, moving a 32-bit long usually requires two machine instructions -- one to move each 16-bit chunk.
Using size_t avoids this performance toll. According to this fantastic article, "Type size_t is a typedef that's an alias for some unsigned integer type, typically unsigned int or unsigned long, but possibly even unsigned long long. Each Standard C implementation is supposed to choose the unsigned integer that's big enough--but no bigger than needed--to represent the size of the largest possible object on the target platform."
The size_t type is the type returned by the sizeof operator. It is an unsigned integer capable of expressing the size in bytes of any memory range supported on the host machine. It is (typically) related to ptrdiff_t in that ptrdiff_t is a signed integer value such that sizeof(ptrdiff_t) and sizeof(size_t) are equal.
When writing C code you should always use size_t whenever dealing with memory ranges.
The int type on the other hand is basically defined as the size of the (signed) integer value that the host machine can use to most efficiently perform integer arithmetic. For example, on many older PC type computers the value sizeof(size_t) would be 4 (bytes) but sizeof(int) would be 2 (byte). 16 bit arithmetic was faster than 32 bit arithmetic, though the CPU could handle a (logical) memory space of up to 4 GiB.
Use the int type only when you care about efficiency as its actual precision depends strongly on both compiler options and machine architecture. In particular the C standard specifies the following invariants: sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) placing no other limitations on the actual representation of the precision available to the programmer for each of these primitive types.
Note: This is NOT the same as in Java (which actually specifies the bit precision for each of the types 'char', 'byte', 'short', 'int' and 'long').
Type size_t must be big enough to store the size of any possible object. Unsigned int doesn't have to satisfy that condition.
For example in 64 bit systems int and unsigned int may be 32 bit wide, but size_t must be big enough to store numbers bigger than 4G
This excerpt from the glibc manual 0.02 may also be relevant when researching the topic:
There is a potential problem with the size_t type and versions of GCC prior to release 2.4. ANSI C requires that size_t always be an unsigned type. For compatibility with existing systems' header files, GCC defines size_t in stddef.h' to be whatever type the system'ssys/types.h' defines it to be. Most Unix systems that define size_t in `sys/types.h', define it to be a signed type. Some code in the library depends on size_t being an unsigned type, and will not work correctly if it is signed.
The GNU C library code which expects size_t to be unsigned is correct. The definition of size_t as a signed type is incorrect. We plan that in version 2.4, GCC will always define size_t as an unsigned type, and the fixincludes' script will massage the system'ssys/types.h' so as not to conflict with this.
In the meantime, we work around this problem by telling GCC explicitly to use an unsigned type for size_t when compiling the GNU C library. `configure' will automatically detect what type GCC uses for size_t arrange to override it if necessary.
If my compiler is set to 32 bit, size_t is nothing other than a typedef for unsigned int. If my compiler is set to 64 bit, size_t is nothing other than a typedef for unsigned long long.
size_t is the size of a pointer.
So in 32 bits or the common ILP32 (integer, long, pointer) model size_t is 32 bits.
and in 64 bits or the common LP64 (long, pointer) model size_t is 64 bits (integers are still 32 bits).
There are other models but these are the ones that g++ use (at least by default)
I'm trying to celebrate 10,000,000 questions on StackOverflow with a simple console application written in C, but I don't want to waste any memory. What's the most efficient way to store the number 10,000,000 in memory?
The type you're looking for is int_least32_t, from stdint.h, which will give you the smallest type with at least 32 bits. This type is guaranteed to exist on C99 implementations.
Exact-width typedefs such as int32_t are not guaranteed to exist, though you'd be hard pressed to find a platform without it.
The number 10000000 (ten million) requires 24 bits to store as an unsigned value.
Most C implementations do not have a 24-bit type. Any implementation that conforms to the 1999 C standard or later must provide the <stdint.h> header, and must define all of:
uint_least8_t
uint_least16_t
uint_least32_t
uint_least64_t
each of which is (an alias for) an unsigned integer type with at least the specified width, such that no narrower integer type has at least the specified width. Of these, uint_least32_t is the narrowest type that's guaranteed to hold the value 10000000.
On the vast majority of C implementations, uint_least32_t is the type you're looking for -- but on an implementation that supports 24-bit integers, there will be a narrower type that satisfies your requirements.
Such an implementation would probably define uint24_t, assuming that it's unsigned 24-bit type has no padding bits. So you could do something like this:
#include <stdint.h>
#ifdef UINT_24_MAX
typedef uint24_t my_type;
#else
typedef uint_least32_t my_type;
#endif
That's still not 100% reliable (for example if there's a 28-bit type but no 24-bit type, this would miss it). In the worst case, it would select uint_least32_t.
If you want to restrict yourself to the predefined types (perhaps because you want to support pre-C99 implementations), you could do this:
#include <limits.h>
#define TEN_MILLION 10000000
#if UCHAR_MAX >= TEN_MILLION
typedef unsigned char my_type;
#elif USHRT_MAX >= TEN_MILLION
typedef unsigned short my_type;
#elif UINT_MAX >= TEN_MILLION
typedef unsigned int my_type;
#else
typedef unsigned long my_type;
#endif
If you merely want the narrowest predefined type that's guaranteed to hold the value 10000000 on all implementations (even if some implementations might have a narrower type that can hold it), use long (int can be a narrow as 16 bits).
If you don't require using an integer type, you can simply define a type that's guaranteed to be 3 bytes wide:
typedef unsigned char my_type[3];
But actually that will be wider than you need of CHAR_BIT > 8:
typedef unsigned char my_type[24 / CHAR_BIT]
but that will fail if 24 is not a multiple of CHAR_BIT.
Finally, your requirement is to represent the number 10000000; you didn't say you need to be able to represent any other numbers:
enum my_type { TEN_MILLION };
Or you can define a 1-bit bitfield with the value 1 denoting 10000000 and the value 0 denoting not 10000000.
Technically a 24-bit integer can store that, but there are no 24-bit primitive types in C. You will have to use a 32-bit int, or a long.
For performance that would be the best approach, wasting 1 unused byte of memory is irrelevant.
Now, if for study purposes you really really want to store 10 million in the smallest piece of memory possible, and you are even willing to make your own data storage method to achieve that, you can store that in 1 byte, by customizing a storage method that follows the example of float. You only need 4 bits to represent 10, and other 3 bits to represent 7, and have in 1 byte all data you need to calculate pow(10, 7);. It even leaves you with an extra free bit you can use as sign.
The largest value that can be stored in an uint16_t is 0xFFFF, which is 65535 in decimal. That is obviously not large enough.
The largest value that can be stored in an uint32_t is 0xFFFFFFFF, which is 4294967295 in decimal. That is obviously large enough.
Looks like you'll need to use uint32_t.
If you want to store a number n > 0 in an unsigned integer data type, then you need at least ⌈lg (n+1)⌉ bits in your integer type. In your case, ⌈lg (10,000,000 + 1)⌉ = 24, so you'd need at least 24 bits in whatever data type you picked.
To the best of my knowledge, the C spec does not include an integer type that holds specifically 24 bits. The closest option would be to use something like uint32_t, but (as was mentioned in a comment) this type might not exist on all compilers. The type int_least32_t is guaranteed to exist, but it might be way larger than necessary.
Alternatively, if you just need it to work on one particular system, your specific compiler may have a compiler-specific data type for 24-bit integers. (Spoiler: it probably doesn't. ^_^)
The non-smart-alecky answer is uint32_t or int32_t.
But if you're really low on memory,
uint8_t millions_of__questions;
But only if you are a fan of fixed-point arithmetic and are willing to deal with some error (or are using some specialized numerical representation scheme). Depends on what you're doing with it after you store it and what other numbers you want to be storable in your "datatype".
struct {
uint16_t low; // Lower 16 bits
uint8_t high; // Upper 8 bits
} my_uint24_t;
This provides 24-bits of storage and can store values up to 16,777,215. It's not a native type and would need to special accessor functions, but it takes less space than a 32-bit integer on most platforms (packing may be required).
uint32_t from <stdint.h> would probably be your go-to data type. Since uint16_t would only be able to store 2^16-1=65535, the next available type is uint32_t.
Note that uint32_t stores unsigned values; use int32_t if you want to store signed numbers as well. You can find more info, e.g., here: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/stdint.h.html
I have ever read that int32_t is exact 32 bits long and int_least32_t only at least 32 bits, but they have both the same typedefs in my stdint.h:
typedef int int_least32_t;
and
typedef int int32_t;
So where is the difference? They exactly the same...
int32_t is signed integer type with width of exactly 32 bits with no padding bits and using 2's complement for negative values.
int_least32_t is smallest signed integer type with width of at least 32 bits.
These are provided only if the implementation directly supports the type.
The typedefs that you are seeing simply means that in your environment both these requirements are satisfied by the standard int type itself. This need not mean that these typedefs are the same on a different environment.
Why do you think that on another computer with different processor, different OS, different version of C standard libs you will see exactly this typedefs?
This 2 types are exactly what you wrote. One of them is 32 bits exactly, another type is at least 32 bit. So one of the possible situations is when both of them are 32 bits and on your particular case you see it in stdint.h. On another system you may see that they are different.
In x86/amd64 world sizeof(long long) is 8.
Let me quote quite insightful 8 year old mail by Zack Weinberg:
Scott Robert Ladd writes:
On a 64-bit AMD64 architecture, GCC defines long long as 64 bits, the
same as a long.
Given that certain 64-bit instructions (multiply) produce 128-bit
results, doesn't it seem logical the long long be defined as 128 bits?
No, for two reasons:
The choice of 64-bit 'long long' has been written into the ABI of
most LP64-model operating systems; we can't unilaterally change it.
This is actually the correct choice, as it removes the aberration
that makes 'long' not the widest basic integral type. There is
lots and lots of code in the wild written to the assumption that
sizeof(long) >= sizeof(size_t) - this is at least potentially
broken by ABIs where long long is wider than long.
(This was an extremely contentious topic during the development of
C99. As best as I can tell from an outside perspective, 'long long'
was only standardized due to pressure from Microsoft who can't for
some reason implement an LP64 model. Everyone else hated the idea
of making 'long' not necessarily the widest basic integral type.)
Best current practice appears to be to provide an "extended integral
type" __int128. This doesn't have the problems of 'long long' because
it's not a basic integral type (in particular, it cannot be used for
size_t).
zw
long long is widest basic integral type. It's 64-bit long on any non-dead-old architectures/ABIs I know. This allows for going with simple cross-platform (well, at least for many 32/64-bit architectures) typedefs:
typedef char s8;
typedef unsigned char u8;
typedef short s16;
typedef unsigned short u16;
typedef int s32;
typedef unsigned int u32;
typedef long long s64;
typedef unsigned long long u64;
that are nicer than intXX_t, because:
they use same underlying type for 64-bit integers on different platforms
allows avoiding verbose PRId64/PRIu64
(I am well aware that Visual C++ supports %lld/%llu only since 2005)
But how portable this solution is can be expressed by answers to the following question.
What are the architectures/ABIs where sizeof(long long) != 8?
If you cannot provide any recent/modern ones, then go ahead with the old ones, but only if they are still in use.
TI TMS320C55x architecture has CHAR_BIT of 16-bit and long long of 40-bit. Although the 40-bit long long violates ISO, sizeof (long long) is different from 8.
Actually nearly all the C99 implementations with CHAR_BIT > 8 have sizeof (long long) != 8.
TMS320C55x Optimizing C/C++ Compiler User’s Guide (2003)
http://www.ti.com/lit/ug/spru281f/spru281f.pdf
"(This was an extremely contentious topic during the development of C99. As best as I can tell from an outside perspective, 'long long' was only standardized due to pressure from Microsoft who can't for some reason implement an LP64 model. Everyone else hated the idea of making 'long' not necessarily the widest basic integral type.)"
It was contentious among Unix vendors, without reference to Microsoft, which had a lot of I16LP32 code, where the only 32-bit integer was long, so they plausibly did not want to change that.
UNIX & other vendors had ILP32 or like Amdahl, Convex, others ILP32LL64, so needed a 64-bit datatype, just as PDP-11s got to be IP16L32 in mid-1970s to get a 32-bit datatype instead of int X[2].
For the detailed history, here's 2006 article in ACM Queue, later reprinted in 2009 CACM. See especially Table 1.
"The Long Road to 64 Bits
Double, double, toil and trouble"
https://queue.acm.org/detail.cfm?id=1165766
Also, if you read C99, I wrote the rationale for long long.
In the meetings described in the paper, we were split between:
IL32LLP64 - leave long as 32-bit
ILP64 - make ints and longs 64, introduce new type for 32
LP64 - make longs 64, leave ints 32
There were good arguments for each, but the argument was effectively settled by fact that the first two companies shipping 64-bit micros both went LP64.
Your "cross-platform" typedefs are just misguided. The correct ones are
#include <stdint.h>
typedef int8_t s8;
typedef uint8_t u8;
typedef int16_t s16;
...
This is related to following question,
How to Declare a 32-bit Integer in C
Several people mentioned int is always 32-bit on most platforms. I am curious if this is true.
Do you know any modern platforms with int of a different size? Ignore dinosaur platforms with 8-bit or 16-bit architectures.
NOTE: I already know how to declare a 32-bit integer from the other question. This one is more like a survey to find out which platforms (CPU/OS/Compiler) supporting integers with other sizes.
As several people have stated, there are no guarantees that an 'int' will be 32 bits, if you want to use variables of a specific size, particularly when writing code that involves bit manipulations, you should use the 'Standard Integer Types' mandated by the c99 specification.
int8_t
uint8_t
int32_t
uint32_t
etc...
they are generally of the form [u]intN_t, where the 'u' specifies that you want an unsigned quantity, and N is the number of bits
the correct typedefs for these should be available in stdint.h on whichever platform you are compiling for, using these allows you to write nice, portable code :-)
"is always 32-bit on most platforms" - what's wrong with that snippet? :-)
The C standard does not mandate the sizes of many of its integral types. It does mandate relative sizes, for example, sizeof(int) >= sizeof(short) and so on. It also mandates minimum ranges but allows for multiple encoding schemes (two's complement, ones' complement, and sign/magnitude).
If you want a specific sized variable, you need to use one suitable for the platform you're running on, such as the use of #ifdef's, something like:
#ifdef LONG_IS_32BITS
typedef long int32;
#else
#ifdef INT_IS_32BITS
typedef int int32;
#else
#error No 32-bit data type available
#endif
#endif
Alternatively, C99 and above allows for exact width integer types intN_t and uintN_t:
The typedef name intN_t designates a signed integer type with width N, no padding bits, and a two's complement representation. Thus, int8_t denotes a signed integer type with a width of exactly 8 bits.
The typedef name uintN_t designates an unsigned integer type with width N. Thus, uint24_t denotes an unsigned integer type with a width of exactly 24 bits.
These types are optional. 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.
At this moment in time, most desktop and server platforms use 32-bit integers, and even many embedded platforms (think handheld ARM or x86) use 32-bit ints. To get to a 16-bit int you have to get very small indeed: think "Berkeley mote" or some of the smaller Atmel Atmega chips. But they are out there.
No. Small embedded systems use 16 bit integers.
It vastly depends on your compiler. Some compile them as 64-bit on 64-bit machines, some compile them as 32-bit. Embedded systems are their own little special ball of wax.
Best thing you can do to check:
printf("%d\n", sizeof(int));
Note that sizeof will print out bytes. Do sizeof(int)*CHAR_BIT to get bits.
Code to print the number of bits for various types:
#include <limits.h>
#include <stdio.h>
int main(void) {
printf("short is %d bits\n", CHAR_BIT * sizeof( short ) );
printf("int is %d bits\n", CHAR_BIT * sizeof( int ) );
printf("long is %d bits\n", CHAR_BIT * sizeof( long ) );
printf("long long is %d bits\n", CHAR_BIT * sizeof(long long) );
return 0;
}
TI are still selling OMAP boards with the C55x DSPs on them, primarily used for video decoding. I believe the supplied compiler for this has a 16 bit int. It is hardly dinosaur (the Nokia 770 was released in 2005), although you can get 32 bit DSPs.
Most code you write, you can safely assume it won't ever be run on a DSP. But perhaps not all.
Well, most ARM-based processors can run Thumb code, which is a 16-bit mode. That includes the yet-only-rumored Android notebooks and the bleeding-edge smartphones.
Also, some graphing calculators use 8-bit processors, and I'd call those fairly modern as well.
If you are also interested in the actual Max/Min Value instead of the number of bits, limits.h contains pretty much everything you want to know.