views:

467

answers:

3

It seems all of them take 4 bytes of space,

so what's the difference?

+11  A: 

First of all, the size of int/long is unspecified. So on your compiler, an int and a long might be the same, but this isn't universal across compilers.

As for the difference between unsigned long and long:

Assuming 4 bytes, a long has the range of -2,147,483,648 to 2,147,483,647. An unsigned long has the range of 0 to 4,294,967,295.

One other difference is with overflow. For a signed type, an overflow has unspecified behavior. But for an unsigned type, overflow is guaranteed to "wrap around."

rlbond
How is the *wrap around* done?
Wrap around is handled as overflow arithmetic. When you hit (in rlbond's example) 4294967296 in an unsigned long, adding 1 will "wrap around" and it will become the minimum value: 0. Adding 2 will wrap around and make it 1, etc.
Dan Story
Seems this kinda stuff can also be done for a signed type,right?
It can be, but as rlbond said, the behavior is undefined when you overflow a signed type. Unsigned types are guaranteed to wrap properly; signed types have no such guarantee and behavior could change from one platform to the next.
Dan Story
`4,294,967,296` should be `4,294,967,295` both in the answer and in the comment by @Dan.
Alok
@Alok: Thanks, I totally missed that somehow! I got it in the signed case, I guess my mind just slipped.
rlbond
@rlbond: yeah, I figured that it was a minor typo, but I mentioned it for completeness/correctness.
Alok
+2  A: 

Well, the difference between unsigned long and long is simple -- the upper bound. Signed long goes from (on an average 32-bit system) about -2.1 billion (-2^31) to +2.1 billion (+2^31), while unsigned long goes from 0 to 4.2 billion (2^32).

It so happens that on many compilers and operating systems (including, apparently, yours), int is also a 32-bit value. But the C++ standard doesn't determine maximum widths for any of these types, only minimum widths. On some systems, int is 16 bits. On some systems, long is 64 bits. A lot of it depends on the processor architecture being targeted, and what its base word size is.

The header limits.h exists to define the maximum capacity of the various types under the current compilation environment, and stdint.h exists to provide environment-independent types of guaranteed width, such as int32_t.

Dan Story
Whatever system it is,`int` and `long` have the same length -- the base word size.Is that right?
No, not at all. On older 16-bit compilers, int is usually 2 bytes while long is 4 bytes. There are no hard and fast rules here when it comes to sizes, only relative ones. char will always be smaller than or equal to short, which will always be smaller than or equal to int, which will always be smaller than or equal to long. Technically you could obey the C++ standard and have all four of them be one byte, though.
Dan Story
How do I choose a right data type when the definition is so vague...
Use limits.h or stdint.h to help you out. If you *know* you need a 32-bit value, use int32_t from stdint.h instead of int or long. That way no matter where you port your code it will always be 32 bits.
Dan Story
Standard C requires int to be at least 16 bits and long to be at least 32 bits. Nowadays there's stdint.h, however, which defines types such as int_fast16_t = a signed integer type that's at least 16 bits (but may be more) and as "fast" on the target platform (e.g. it may often be 32 bits on modern computers). These types should be used if you have particular demands on the size. See stdint.h and limits.h on e.g. wikipedia.
Arkku
+3  A: 

The C language specification allows the implementation of int and long types to vary from one platform to another within a few constraints. This variability is a headache for cross-platform code, but it is also an asset because it enables the informed programmer to balance their design goals between native processor speed and full numeric range on hardware architectures that don't offer both.

In general, "int" is supposed to map a machine register size of the target CPU architecture's machine, so that loading, storing, and operating on the int type data should translate directly into operations that use the target processor's native registers.

Int can be less than the machine register size in the interest of saving memory space (big ints take up twice as much RAM as little ints). It's common to see int as a 32 bit entity even on 64 bit architectures where compatibility with older systems and memory efficiency are high priorities.

"long" can be the same size or larger than "int" depending on the target architecture's register sizes. Operations on "long" may be implemented in software if the target architecture doesn't support values that large in its native machine registers.

CPU chips designed for power efficiency or embedded devices are where you will find distinctions between int and long these days. Compilers for general purpose CPUs like in your desktop or laptop PC generally treat int and long as the same size because the CPU efficiently uses 32 bit registers. On smaller devices such as cell phones the CPU may be built to handle 16 bit data more naturally and have to work hard to handle 32 bit or larger data.

Fewer bits per register means fewer circuits required on the chip, fewer data lines to move data in and out of the chip, lower power consumption and smaller chip die size, all of which make for a lower cost (in $ and in watts) device.

In such an architecture, you will most likely find int to be 16 bits in size and long to be 32 bits in size. There may also be a performance penalty associated with using longs, caused by either wait states to load the 32 bits in multiple reads across a 16 bit data bus, or caused by implementing long operations (addition, subtraction, etc) in software if the native hardware doesn't support such operations in hardware.

As a general rule, the only thing you can assume about ints and longs is that the range of int should always be less than or equal to long on any architecture. You should also assume that someday your code will be recompiled for a different architecture where whatever relationship you currently see between int and long no longer exists.

This is why you should be careful to keep ints separate from longs even in everyday mundane coding. They may be completely assignment compatible today because their implementation details for your current hardware platform coincide, but that coincidence is not guaranteed across all platforms.

dthorpe