4

I have a large number that loops from 0 to 65535 (I chose 16 bits simply to have a nice cutting off point). I'm incrementing an int, and there's an if statement that checks if the int is 65536. If it is, it sets the int to 0; a little kludgy, but it works. I know it would be much more efficient to just use a short int and let it overflow, but I initially didn't do that because a short is not guaranteed to be 2 bytes, it's just fairly likely.

This is C code running on a linux (ubuntu) machine. If I were to use a short and later decided to run this program on another OS (or say, run it on a 64-bit machine, since I'm testing on a 32-bit one now), is there a pretty good chance that my short will still be 2 bytes? I can easily test it on a few different machines, but some of the people here have worked with a LOT of computers. Is there a terrible pitfall I should be watching out for?

cost
  • 4,420
  • 8
  • 48
  • 80
  • 1
    You should change your title to say "2 bytes". – ClosureCowboy Feb 13 '11 at 19:06
  • why do you think it will be "much more efficient"? for 32 (or 64) bit systems there will be no difference. – Andrey Feb 13 '11 at 19:07
  • does the compiler not have standard macros that you can use like INT and then corresponding MAX_INT? – Aaron Anodide Feb 13 '11 at 19:08
  • @Andrey - I say much more efficient because I won't need to check the size of the int every time the int is incremented. This saves me from doing a lot of if statements if the number just rolls back over to 0 automatically – cost Feb 13 '11 at 19:10
  • 1
    You shouldn't assume anything not clearly spelled out in the spec if you care about a bit of portability ;) –  Feb 13 '11 at 19:12

8 Answers8

7

There is no guarantee of the size of any of the built-in types like int, char and the like. (See for example this question, which is about C++, but is also accurate for C as far as I know in this regard)

If you need fixed-size integer types, include C99's <stdint.h> and use the fixed-width typesdefined there.

Community
  • 1
  • 1
rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • Yes, there are guarantees. See section 5.2.4.2 Numerical limits. The question is about ranges that C types are guaranteed to hold and this is exactly what is provided in that section. – Pascal Cuoq Feb 13 '11 at 20:01
  • @Pascal: the OP specifically mentions he wants to overflow a `short`, and the standard does not give it an absolute size, only relative to other data types. – rubenvb Feb 13 '11 at 20:09
  • However, even uint16_t may only be one byte, when CHAR_BIT=16. – user611775 Feb 13 '11 at 20:16
  • @user611775: but at least it will still be the expected 16 bits wide, and overflow when the OP expects it to overflow... – rubenvb Feb 14 '11 at 18:56
  • size of `char` (`signed char`, `unsigned char` ) is guaranteed to be 1 byte (by definition). – Aykhan Hagverdili Jun 24 '21 at 14:50
5

Short is 16 bits on the vast majority of compilers. If at all reasonable, I'd probably use a bit-field for the job:

struct { 
    unsigned short my_number : 16;
};

In a typical case where short is 16 bits anyway, this won't impose any overhead -- and in the rare case that some extra code needs to be inserted to clamp the value to the right range, this handles that automatically.

The only shortcoming is that you can only have a bit-field inside a struct.

Edit: It's unfortunate that @earlz deleted his answer, because his idea was actually better than he thought: if a C99 implementation has a 16-bit unsigned integer type, it's required to provide uint16_t as a typedef for that type. If provided, this must be exactly 16 bits wide. There's also a uint_least16_t that fits his description (at least 16 bits wide, but could be more).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
3

No, the only thing you can assume is that shorts are not larger than ints.

If you want to wrap around to 0 after 65535 without a test, you can do it this way:

unsigned int i;
...

i = (i + 1) & 0xffff;
Ferruccio
  • 98,941
  • 38
  • 226
  • 299
  • I am curious about the downvote. Am I missing something obvious here? – Ferruccio Feb 13 '11 at 19:26
  • I didn't downvote, but it's not the *only* thing you can do (see other answers), and some people (not me) don't like to see bitwise operations whatever the provocation. –  Feb 13 '11 at 19:41
  • Extra note - there's a small outside chance your code will fail. This will occur if your platform has 16 bit integers (very rare these days, but still AFAIK legal). The signed integer representation isn't specified, so you can't assume twos complement, and some compilers exploit the standards-undefined overflow behaviour for "optimisation" purposes. Quotes because doing something unintended instead of something intended isn't optimisation IMO, however quick, and there's a long history of bit-fiddling in C irrespective of the lack of standard-mandated guarantees. –  Feb 13 '11 at 19:45
  • Change it to an unsigned int and you're probably OK - so long as there are no platforms with 15 bit unsigned ints. Oh - and add the 'u' suffix to the '0xffff' to be really sure. –  Feb 13 '11 at 19:47
3

There's no guarantee that short is 16 bits - e.g. I've used a compiler that used 32 bits for a short because it was much more efficient to do this than use 16 bits. (On ARM architecture)

However, it's dead easy to use a type that is guaranteed to be 16 bits, and you can add an assertion check that will warn you as soon as you try to use a compiler where this isn't true:

ASSERT(sizeof(short) == 2);
Jason Williams
  • 56,972
  • 11
  • 108
  • 137
  • I won't be running this on a bunch of computers, but I didn't think of this. It will be a nice way to check if I do decide to do it this way. – cost Feb 13 '11 at 20:13
2

A short is going to be however long sizeof says it is. The C standard says that a short is required to be at least sixteen bits. It is not required to be smaller than an int, though it often is.

2-bits
  • 453
  • 6
  • 12
0

Find the platform MAX_SHORT by using sizeof(short), and iterate until you hit that.

PrettyPrincessKitty FS
  • 6,117
  • 5
  • 36
  • 51
0

If you obey C99, then you can assume safely that:

a `short int` may have a minimum value of `-32767`
                         maximum value of `+32767`
an `unsigned short int` may have a minimum value of `0`
                                   maximum value of `65535`

And so on, as witnessed in 5.2.4.2.1 Sizes of integer types <limits.h> of the standard. Noting of course that the standard explicitly notes that the maximum values defined in said section, are to be the size of, or smaller than the implementation defined sizes. Therefore, the size of a short or unsigned short, may be larger than what I just posted above. However, it will not be larger than an int.

jer
  • 20,094
  • 5
  • 45
  • 69
  • I don't think so, as the size of a short is platform/implementation dependent. The section you're citing also states: *Their implementation-defined values shall be equal or greater in magnitude (absolute value) to those shown, with the same sign.* (note the *or greater*). – DarkDust Feb 13 '11 at 19:42
  • Which is what I said above, "noting of course that the standard explicitly notes that the maximum values defined in said section, are to be the size of, or smaller than the implementation defined sizes." i.e., the implementation is free to define their own sizes, but they must be greater than the values they specify. – jer Feb 13 '11 at 20:00
-1

Use uint16_t, or if you insist you can use a larger type and perform x %= 65536; or x &= 65535 on each iteration. I guarantee this is a lot faster than performing a conditional to reset it to zero.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • 2
    Shouldn't it be `x &= 65535` (2^16 - 1) ? – DarkDust Feb 13 '11 at 19:36
  • I'd be careful with the *guarantee it will be faster* - Some architectures like the ARM might prove you wrong. – tofro Jun 21 '16 at 05:21
  • @tofro: Then that would be a compiler bug. The compiler should generate whichever version is faster. – R.. GitHub STOP HELPING ICE Jun 21 '16 at 13:24
  • @R.. If you are trying to trick around using modulo arithmetic or fixed types, you actually *forcing* the compiler to do what you want. Just use a simple `for` loop and a type close to the machine's register size (which would normally be `int`) and you leave all the optimization options to the compiler. – tofro Jun 21 '16 at 17:31