I am trying to port a C program to a SPARC architecture that has
the following type declaration
#include <stdint.h>
typedef uint32_t WORD ;
typedef uint64_t DWORD ;
The trouble is, that the compiler tells me that stdint.h cant be found. Hence,
I redefined those datatypes as follows:
unsigned int WORD;
unsigned long DWORD;
This seems for me the straightforward declaration, but the program is not expecting as it should. Did I maybe miss something?
Thanks
<stdint.h> and the types uint32_t and uint64_t are "new" in ISO/IEC 9899:1999. Your compiler may only conform to the previous version of the standard.
If you are sure that unsigned int and unsigned long are 32-bit and 64-bit respectively then you shouldn't have any problems (at least not ones due to the typedefs themselves). As you are, this may not be the case. Do you know (or can you find out) if your compiler supports unsigned long long?
I'm guessing that unsigned int is probably 32-bit, how old is your SPARC?
If your compiler/OS does not have <stdint.h> then the best thing to do is implement your own version of this header rather than not modify the code you're trying to port. You probably only need a subset of the types that are normally defined in <stdint.h>, e.g.
//
// stdint.h
//
typedef int int32_t; // signed 32 bit int
typedef unsigned long long uint64_t; // unsigned 64 bit int
(obviously you need to know the sizes of the various integer types on your particular platform to do this correctly).
So, you need an integer that's 32 bit and another that's 64 bit.
It might be that int and longs are the same on your architecture, and if your compiler supports long long, that might be 64 bit while int might be 32 bit. Check your compiler docs for what it supports, and if it has any extension (e.g. some compilers might provide an __int64 type). This could be what you need:
typedef unsigned int WORD;
typedef unsigned long long DWORD;
Anyway, I'd write a small program to verify the sizes of integers on your host, so you can pick the correct one , that is printf the sizeof(int), sizeof(long) and so on. (On a sparc host CHAR_BIT will be 8, so it's all atleast a multple of 8 bits. )
Also, since you're porting to a sparc host, make sure your code is not messing up somewhere regarding endianess
Related
I read that stdint.h is used for portability, but I'm confused.
If I wrote a program on a 32-bit system, uint32_t (unsigned int) is 4-bytes.
But when this program is run on 16-bit system, int is 2bytes and uint32_t (unsigned int) is 2bytes.
I think portability is not guaranteed in this case.
Is there anything I am understanding wrong?
Is there any thing I am understanding wrong?
Yes.
Type uint32_t is always an unsigned integer type with exactly 32 bits, none of them padding bits. On many modern systems that corresponds to type unsigned int, but on others it might correspond to a different type, such as unsigned long int. On systems that do not have a type with the correct properties, it is not defined at all.
The point of uint32_t and the other explicit-width data types from stdint.h is exactly to address the issue you raise, that (for example) unsigned int has a different size on different machines.
A uint32_t and a uint16_t are distinct types from int.
While the size of int may vary, a uint32_t is always 32 bit and a uint16_t is always 16 bit.
I just wrote the following function to determine the endianness of the machine architecture (writing for an ARM Cortex-M7 architecture based MCU though, but wanted functionality to make the code portable):
uint8_t is_little_endian()
{
static const union test {
uint32_t num;
uint8_t bytes[sizeof(uint32_t)];
} p = {.num = 1U };
return (p.bytes[0] == 1U);
}
I was just wanting to know if there will be any false results if I use unsigned int and char here instead of uint32_t and uint8_t in the above code? If yes, why?
To answer your immediate question, unsigned and char will work just as well if CHAR_BIT < 16. That's because the C standard requires an unsigned to have at least 16 value bits and every type must have a storage size that's a multiple of a char (a byte). So as long as your char has fewer than 16 bits, an unsigned must consist of at least 2 bytes and the endianness check will work this way.
Using char actually has the benefit that it's allowed to alias any other type. So I'd suggest something like this:
#include <limits.h>
#if CHAR_BIT > 15
#error exotic platform
#endif
int is_little_endian(void)
{
unsigned x = 1U;
unsigned char *r = (unsigned char *)&x;
return !!*r;
}
I used unsigned char here just to be sure.
Be aware this assumes there's no exotic byte order (like "middle-endian"). Also, I personally think such code is a waste of space in the program, if you really need endianness information, it's probably better to have your build system determine it for your target and just #define it (e.g. in a config.h file).
I was just wanting to know if there will be false results if I use
unsigned int and char here instead of uint32_t and uint8_t? If
yes, why?
Yes, it may.
Types mentioned(unsigned int and char) are implementation-defined. It may depend on compiler, machine, compiler options etc. If you look at the types declared in stdint.h. This is part of the standard library, so it is expected (though technically not guaranteed) to be available everywhere. Among the types declared here are int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, and uint64_t.
You can simply return ntohs(12345) != 12345.
I came across the data type int32_t in a C program recently. I know that it stores 32 bits, but don't int and int32 do the same?
Also, I want to use char in a program. Can I use int8_t instead? What is the difference?
To summarize: what is the difference between int32, int, int32_t, int8 and int8_t in C?
Between int32 and int32_t, (and likewise between int8 and int8_t) the difference is pretty simple: the C standard defines int8_t and int32_t, but does not define anything named int8 or int32 -- the latter (if they exist at all) is probably from some other header or library (most likely predates the addition of int8_t and int32_t in C99).
Plain int is quite a bit different from the others. Where int8_t and int32_t each have a specified size, int can be any size >= 16 bits. At different times, both 16 bits and 32 bits have been reasonably common (and for a 64-bit implementation, it should probably be 64 bits).
On the other hand, int is guaranteed to be present in every implementation of C, where int8_t and int32_t are not. It's probably open to question whether this matters to you though. If you use C on small embedded systems and/or older compilers, it may be a problem. If you use it primarily with a modern compiler on desktop/server machines, it probably won't be.
Oops -- missed the part about char. You'd use int8_t instead of char if (and only if) you want an integer type guaranteed to be exactly 8 bits in size. If you want to store characters, you probably want to use char instead. Its size can vary (in terms of number of bits) but it's guaranteed to be exactly one byte. One slight oddity though: there's no guarantee about whether a plain char is signed or unsigned (and many compilers can make it either one, depending on a compile-time flag). If you need to ensure its being either signed or unsigned, you need to specify that explicitly.
The _t data types are typedef types in the stdint.h header, while int is an in built fundamental data type. This make the _t available only if stdint.h exists. int on the other hand is guaranteed to exist.
Always keep in mind that 'size' is variable if not explicitly specified so if you declare
int i = 10;
On some systems it may result in 16-bit integer by compiler and on some others it may result in 32-bit integer (or 64-bit integer on newer systems).
In embedded environments this may end up in weird results (especially while handling memory mapped I/O or may be consider a simple array situation), so it is highly recommended to specify fixed size variables. In legacy systems you may come across
typedef short INT16;
typedef int INT32;
typedef long INT64;
Starting from C99, the designers added stdint.h header file that essentially leverages similar typedefs.
On a windows based system, you may see entries in stdin.h header file as
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef unsigned char uint8_t;
There is quite more to that like minimum width integer or exact width integer types, I think it is not a bad thing to explore stdint.h for a better understanding.
I am developing a program for an STM32Fx cortex-M3 series processor. In stdint.h the following are defined:
typedef unsigned int uint_fast32_t;
typedef uint32_t uint_least32_t;
typedef unsigned long uint32_t;
As I understand it.
[u]int_fast[n]_t will give you the fastest data type of at least n bits.
[u]int_least[n]_t will give you the smallest data type of at least n bits.
[u]int[n]_t will give you the data type of exactly n bits.
Also as far as i know sizeof(unsigned int) <= sizeof(unsigned long) and UINT_MAX <= ULONG_MAX - always.
Thus I would expect uint_fast32_t to be a data type with a size equal to or greater than the size of uint32_t.
In the case of the cortex-M3 sizeof(unsigned int) == sizeof(unsigned long) == 4. So the above definitions are 'correct' in terms of size.
But why are they not defined in a way that is consistent with the names and logical sizes of the underlying data types i.e.
typedef unsigned long uint_fast32_t;
typedef unsigned int uint_least32_t;
typedef uint_fast32_t uint32_t;
Can someone please clarify the selection of the underlying types?
Given that 'long' and 'int' are the same size, why not use the same data type for all three definitions?
typedef unsigned int uint_fast32_t;
typedef unsigned int uint_least32_t;
typedef unsigned int uint32_t;
The case is, it is only guaranteed that
sizeof(long) >= sizeof(int)
and it is not guaranteed that it is actually any longer. On a lot of systems, int is usually as big as long.
See my answer to your other question.
Basically, it doesn't matter which type is used. Given that int and long are the same size and have the same representation and other characteristics, the implementer can choose either type for int32_t, int_fast32_t, and int_least32_t, and likewise for the corresponding unsigned versions.
(It's possible that the particular choices could be influenced by a perceived need to use the same header for implementations with different sizes for int and long, but I don't see how the particular definitions you quoted would achieve that.)
As long as the types are the right size and meet all the other requirements imposed by the standard, and as long as you don't write code that depends on, for example, int32_t being compatible with int, or with long, it doesn't matter.
The particular choices made were likely an arbitrary whim of the implementer -- which is perfectly acceptable. Or perhaps that header file was modified by two or more developers who had different ideas about which type is best.
I want to know how to announce int to make sure it's 4 bytes or short in 2 bytes no matter on what platform. Does C99 have rules about this?
C99 doesn't say much about this, but you can check whether sizeof(int) == 4, or you can use fixed size types like uint32_t (32 bits unsigned integer). They are defined in stdint.h
If you are using C99 and require integer types of a given size, include stdint.h. It defines types such as uint32_t for an unsigned integer of exactly 32-bits, and uint_fast32_t for an unsigned integer of at least 32 bits and “fast” on the target machine by some definition of fast.
Edit: Remember that you can also use bitfields to get a specific number of bits (though it may not give the best performance, especially with “strange” sizes, and most aspects are implementation-defined):
typedef struct {
unsigned four_bytes:32;
unsigned two_bytes:16;
unsigned three_bits:3;
unsigned five_bits:5;
} my_message_t;
Edit 2: Also remember that sizeof returns the number of chars. It's theoretically possible (though very unlikely these days) that char is not 8 bits; the number of bits in a char is defined as CHAR_BIT in limits.h.
Try the INT_MAX constant in limits.h
Do you want to require it to be 4 bytes?
If you just want to see the size of int as it is compiled on each platform then you can just do sizeof(int).
sizeof (int) will return the number of bytes an int occupies in memory on the current system.
I assume you want something beyond just the obvious sizeof (int) == 4 check. Likely you want some compile-time check.
In C++, you could use BOOST_STATIC_ASSERT.
In C, you can make compile-time assertions by writing code that tries to create negatively-sized arrays on failure or that tries to create switch statements with redefined cases. See this stackoverflow question for examples: Ways to ASSERT expressions at build time in C
You can use sizeof(int), but you can never assume how large an int is. The C specification doesn't put any assumptions on the size of an int, except that it must be greater or equal to the size of a short (which must be greater or equal to the size of a char).
Often the size of an int aligns to the underlying hardware. This means an int is typically the same as a word, where a word is the functional size of data fetched off the memory bus (or sometimes the CPU register width). It doesn't have to be the same as a word, but the earliest notes I have indicated it should be the preferred size for memory transfer (which is typically a word).
In the past, there have been 18 bit ints (PDP-8) and 24 bit ints (PDP-15). There have been architectures with 36 bit word sizes (PDP-11) but I can't recall what their int size turned out to be.
On Linux platforms, you can peek in
#include <sys/types.h>
to get the actual bit count for each type.
I found last night that visual studio 2008 doesn't support C99 well, and it doesn't support stdint.h. BUT they have their own types. here is a example:
#ifdef _MSC_VER
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif