What's the difference between unsigned long/long/int in c/c++?

53,183

Solution 1

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."

Solution 2

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.

Solution 3

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 - 1), while unsigned long goes from 0 to 4.2 billion (2^32 - 1).

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.

Share:
53,183
user198729
Author by

user198729

Updated on February 18, 2020

Comments

  • user198729
    user198729 over 4 years

    It seems all of them take 4 bytes of space,

    so what's the difference?

  • user198729
    user198729 about 14 years
    Whatever system it is,int and long have the same length -- the base word size.Is that right?
  • Dan Story
    Dan Story about 14 years
    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
    Dan Story about 14 years
    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.
  • user198729
    user198729 about 14 years
    Seems this kinda stuff can also be done for a signed type,right?
  • Dan Story
    Dan Story about 14 years
    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
    Dan Story about 14 years
    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.
  • Alok Singhal
    Alok Singhal about 14 years
    4,294,967,296 should be 4,294,967,295 both in the answer and in the comment by @Dan.
  • rlbond
    rlbond about 14 years
    @Alok: Thanks, I totally missed that somehow! I got it in the signed case, I guess my mind just slipped.
  • Alok Singhal
    Alok Singhal about 14 years
    @rlbond: yeah, I figured that it was a minor typo, but I mentioned it for completeness/correctness.
  • Arkku
    Arkku about 14 years
    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.
  • 12431234123412341234123
    12431234123412341234123 over 7 years
    "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." can by wrong, a byte can have more than 8 bits and so the range can be bigger, the minimum long value is at maximum -2 147 483 647 and not 2 147 483 648 (c allow integers with signed zero).
  • rlbond
    rlbond over 7 years
    I suppose I should have said "assuming four 8-bit bytes" instead.