When you need an integral type. . .

T

Tomás

When you simply want to store a number, what integral type do you use?

For instance, let's say we have the following in a Poker game:

struct Card
{
enum Suit { Hearts, Diamonds, Spades, Clubs } suit;

int value;
};


Looking at the "value" variable above, it's range needs to be 0 to 51.

How many people would use an "int"? How many people would use an
"unsigned char"?

Upon first thought, I would presume that the most appropriate choice
would be "unsigned char", as the number shall always be positive, and it
has sufficient range.

I myself always use unsigned integral types unless I strictly need a
signed type. For instance:

unsigned GetDaysInMonth( unsigned month );

Nonetheless, I see that a lot of people use "int" everywhere, even when
the number shouldn't ever be negative.

Is it too pedantic to use an "unsigned char" to store the card's numeric
value? If so why?

Basically, what makes you choose a particular integral type?

Lastly, do you ever use an enum to get the desired range, as in:

enum CardValue { Ace = 1, King = 13 };


-Tomás
 
P

Phlip

Tomás said:
When you simply want to store a number, what integral type do you use?

For instance, let's say we have the following in a Poker game:

struct Card
{
enum Suit { Hearts, Diamonds, Spades, Clubs } suit;

int value;
};


Looking at the "value" variable above, it's range needs to be 0 to 51.

Make it an 'int'. Make sure your program is easy to change. If you ever
encounter a reason to change the int, you might then observe these
rationales:

- CPUs often - but not always - process ints faster than smaller things

- an 'enum' will be slightly more typesafe, and will only contain
enough bits to count to 51.
Is it too pedantic to use an "unsigned char" to store the card's numeric
value? If so why?

If you feel like writing that, write it. Then make sure you can change it in
the future. Software design is not about carving marble.
Basically, what makes you choose a particular integral type?

The less I have to think about such low-level things, the more energy I can
devote to a program's structure and behavior.

C++ is a high-level language with low-level modes that are available when
you need.
Lastly, do you ever use an enum to get the desired range, as in:

enum CardValue { Ace = 1, King = 13 };

For most card games, the names of the cards are just that - names. The Queen
doesn't run the palace while the King's away, or whatever real Queens and
Kings do. So the name "Queen", the picture, and such, should be attributes
of an array at index 12.

Your system, however, doesn't allow CardValue to be typesafe for any cards
besides Ace and King.
 
D

Daniel T.

"Tomás said:
When you simply want to store a number, what integral type do you use?

For instance, let's say we have the following in a Poker game:

struct Card
{
enum Suit { Hearts, Diamonds, Spades, Clubs } suit;

int value;
};


Looking at the "value" variable above, it's range needs to be 0 to 51.

How many people would use an "int"? How many people would use an
"unsigned char"?

Upon first thought, I would presume that the most appropriate choice
would be "unsigned char", as the number shall always be positive, and it
has sufficient range.

I myself always use unsigned integral types unless I strictly need a
signed type. For instance:

unsigned GetDaysInMonth( unsigned month );

Nonetheless, I see that a lot of people use "int" everywhere, even when
the number shouldn't ever be negative.

Is it too pedantic to use an "unsigned char" to store the card's numeric
value? If so why?

First, the pros disagree as to whether using unsigned types just because
"it will never be less than 0" is a good idea. For example, the FAQ
says: "It's probably a good idea to use unsigned integers for variables
that are always >= 0... The main reason for this is it requires less
code, at least if you are careful to check your ranges." whereas
Stroustrup says: "Attempts to ensure that some values are positive by
declaring variables unsigned will typically be defeated by the implicit
conversion rules."

When the pro's don't agree, it's probably a religious issue, like brace
placement. That said, I use 'int' unless I specifically need another
type. If I remember right, the size of int is decreed by the standard to
be the "most natural" type for the system, ie likely the fastest.
Basically, what makes you choose a particular integral type?

If int doesn't cut it, I change to a type that does.
Lastly, do you ever use an enum to get the desired range, as in:

enum CardValue { Ace = 1, King = 13 };

No. Although I have been known to create a class that holds an int but
doesn't allow that int to equal certain values.
 
J

Jaspreet

Tomás said:
When you simply want to store a number, what integral type do you use?

For instance, let's say we have the following in a Poker game:

struct Card
{
enum Suit { Hearts, Diamonds, Spades, Clubs } suit;

int value;
};


Looking at the "value" variable above, it's range needs to be 0 to 51.

How many people would use an "int"? How many people would use an
"unsigned char"?

Upon first thought, I would presume that the most appropriate choice
would be "unsigned char", as the number shall always be positive, and it
has sufficient range.
<snip>

Apologies for asking such a basic point but will it not be better to
use a bit field in this case ? If the range is going to stay 51 or lets
say someone invents a new card game which uses a pack of 2 cards, isn't
using a bit field going to be better than using a char or an unsigned
int ?

Again apologies for being slightly OT but just had this query in mind.
Hope the experts won't mind asking such a basic query.
 
M

Me

Tomás said:
When you simply want to store a number, what integral type do you use?

A lot of it is context dependent. If I need to store an array index,
it's always size_t, if I need to store a coordinate it will be
typedeffed to whatever the graphics library I use picks, etc. If it
doesn't matter (as long as the minimum guaranteed range fits), I'll
stick with unsigned int unless I really need negative integers. If I
*really* care about packing, I'll consider the smaller types.
For instance, let's say we have the following in a Poker game:

struct Card
{
enum Suit { Hearts, Diamonds, Spades, Clubs } suit;

int value;
};


Looking at the "value" variable above, it's range needs to be 0 to 51.

To me, it looks like the range needs to be 0 to 12.
How many people would use an "int"? How many people would use an
"unsigned char"?

I would use an unsigned int and get rid of the suit variable since you
can calculate it with the / operator. I might also consider adding
sentinel values because they come in handy sometimes.
Upon first thought, I would presume that the most appropriate choice
would be "unsigned char", as the number shall always be positive, and it
has sufficient range.

I myself always use unsigned integral types unless I strictly need a
signed type. For instance:

unsigned GetDaysInMonth( unsigned month );

Sounds like something I would do. But this is just working around the
fact that C++ sucks. If the constexpr proposal is accepted, it will
finally let you add an integer to an enum and return the enum **but
have it work at compile time if you feed it integral constant
expressions**.
Nonetheless, I see that a lot of people use "int" everywhere, even when
the number shouldn't ever be negative.

But of these examples:
- how many of the programmers would you consider expert worthy?
- how would this code fair on non-nice platforms like the DS9000?
- is this code defensive against (theoretical) changes by the C/C++
standards committee, non-standards conforming compilers, or weird
compiler extensions? For example if they decide change the value
preserving promotion rules to unsigned preserving.
- how localized is this? If it only affects (lets say) 2 functions,
then you're seeing a good programmer at work. But if it affects a much
larger amount of code (worst being if it affects more than 1
translation unit), this programmer either is ignorant or lazy.

Even C is guilty of this kind of stupidity. As the standard evolved:

- you have strcpy which copies the string as an unsigned char, but 0 as
a plain char is allowed to have more than one object representation on
certain platforms. Whoops.
- some functions return (unsigned) char converted to int, what if
(unsigned) char's range is larger? Whoops.
- etc.
Is it too pedantic to use an "unsigned char" to store the card's numeric
value? If so why? Basically, what makes you choose a particular integral type?

For this example, I'd either use unsigned char or unsigned int
depending on how I'm feeling that day (and today, I'm in an unsigned
int kind of mood). The biggest drawback of using unsigned char is that
the character types are the magic "alias all type", so if you use a
pointer or reference of a character type, the compiler has to work
harder to prove it doesn't alias other variables or else you end up
with poorer code generated.
Lastly, do you ever use an enum to get the desired range, as in:

enum CardValue { Ace = 1, King = 13 };

Sometimes, but locally. I find it's much better to use member functions
that calculates this stuff because you can change the implementation
later on without affecting much code. But like I said above, C++ would
be much better with something like constexpr so the main problem with
the above approach gets eliminated.
 
Z

Zara

When you simply want to store a number, what integral type do you use?

For instance, let's say we have the following in a Poker game:

struct Card
{
enum Suit { Hearts, Diamonds, Spades, Clubs } suit;

int value;
};


Looking at the "value" variable above, it's range needs to be 0 to 51.
<...>

I would use:

struct Card {
enum Suite { Hearts, Diamonds, Spades Clubs } suite;
enum FaceValue {Ace=1, Jack=11, Queen=12, King=13 } faceValue;
int value {return (faceValue-Ace)+(King*suite);}
};

Or shouldn't I?

Zara
 
G

Gavin Deane

Tomás said:
When you simply want to store a number, what integral type do you use?
int

For instance, let's say we have the following in a Poker game:

struct Card
{
enum Suit { Hearts, Diamonds, Spades, Clubs } suit;

That can be just
enum Suit { Hearts, Diamonds, Spades, Clubs };
int value;
};


Looking at the "value" variable above, it's range needs to be 0 to 51.

Not 0 to 12?
How many people would use an "int"? How many people would use an
"unsigned char"?

I wouldn't use unsigned char. I wouldn't use unsigned anything.
Upon first thought, I would presume that the most appropriate choice
would be "unsigned char", as the number shall always be positive, and it
has sufficient range.

Personally, the question of "what's the smallest type I can get away
with" wouldn't even occur to me until I'd proved there was a memory
problem. But if using the smallest type possible is your goal, then a
char type is the most appropriate. Presumably you're using the smallest
type possible because you want to minimise memory footprint and you
don't mind if execution speed is compromised. And memory footprint must
be a serious enough concern that you're prepared to go away from the
idiomatic natural type.

I don't know why you would use unsigned just because the number shall
always be positive. That's by no means universally accepted as good
practice. What do you think it gains you? If you write the code
correctly, you can use a signed type and no negative values will end up
stored in it. If you write a bug in the code that tries to store a
negative number, using an unsigned type won't always protect you.
I myself always use unsigned integral types unless I strictly need a
signed type. For instance:

unsigned GetDaysInMonth( unsigned month );

Nonetheless, I see that a lot of people use "int" everywhere, even when
the number shouldn't ever be negative.

Because unsigned types do not protect both ends of the range. They
sometimes protect the bottom end of the range and offer no protection
at the top end of the range. I never need that sort of incomplete
protection. If I need to police the values at all, I need to police
them properly. So I'll use a different technique. Your Suit enum above
is a simple example. Why did you choose an enum for that instead of an
unsigned char that holds the values 0, 1, 2 and 3? There's also the
problem that unsigned arithmetic doesn't do what you expect if you
subtract the number of days in March from the number of days in
February.
Is it too pedantic to use an "unsigned char" to store the card's numeric
value? If so why?

I think so, for the reasons above. YMMV.
Basically, what makes you choose a particular integral type?

int unless and until I have either:
proof that memory usage is unacceptable, in which case I'd use a
smaller type, or
proof that the values I'm using don't fit inside int, in which case
I'd use long.

usinged only for bit twiddling.
Lastly, do you ever use an enum to get the desired range, as in:

enum CardValue { Ace = 1, King = 13 };

If you just need the min and max values, I wouldn't use an enum,
because you aren't enumerating anything. Simply define two constants.

const int MinimumCardValue = 1;
const int MaximumCardValue = 13;

Gavin Deane
 
G

Geo

Tomás said:
When you simply want to store a number, what integral type do you use?

For instance, let's say we have the following in a Poker game:

struct Card
{
enum Suit { Hearts, Diamonds, Spades, Clubs } suit;

int value;
};


Looking at the "value" variable above, it's range needs to be 0 to 51.

How many people would use an "int"? How many people would use an
"unsigned char"?

Upon first thought, I would presume that the most appropriate choice
would be "unsigned char", as the number shall always be positive, and it
has sufficient range.

I myself always use unsigned integral types unless I strictly need a
signed type. For instance:

unsigned GetDaysInMonth( unsigned month );

Nonetheless, I see that a lot of people use "int" everywhere, even when
the number shouldn't ever be negative.

Is it too pedantic to use an "unsigned char" to store the card's numeric
value? If so why?

Basically, what makes you choose a particular integral type?

Lastly, do you ever use an enum to get the desired range, as in:

enum CardValue { Ace = 1, King = 13 };


-Tomás

If you feel you need this level of type safety, perhaps you should
consider writting it in Ada :)
 
B

Bo Persson

Daniel T. said:
First, the pros disagree as to whether using unsigned types just
because
"it will never be less than 0" is a good idea. For example, the FAQ
says: "It's probably a good idea to use unsigned integers for
variables
that are always >= 0... The main reason for this is it requires less
code, at least if you are careful to check your ranges." whereas
Stroustrup says: "Attempts to ensure that some values are positive
by
declaring variables unsigned will typically be defeated by the
implicit
conversion rules."

The problem is that nothing stops you from assigning a negative value
to an unsigned variable. Then what?!
When the pro's don't agree, it's probably a religious issue, like
brace
placement. That said, I use 'int' unless I specifically need another
type. If I remember right, the size of int is decreed by the
standard to
be the "most natural" type for the system, ie likely the fastest.

Right. If you don't have some *very* specific requirements, an int
will do.

And who says that speed is important here? Or space? :)


Bo Persson
 
D

Daniel T.

"Bo Persson" <[email protected]> said:
The problem is that nothing stops you from assigning a negative value
to an unsigned variable. Then what?!

That's the question isn't it. I think it was last month the signed vs
unsigned debate came up, and someone (I don't remember who) make a
useful observation IMO. With any type, you have to be careful when
working at the borders of its range. Using int those borders are likely
to be very far from the "normal usage range" however when using an
unsigned type, the low border is right at the edge of your usage range.

I mean, given the code:

result = a - b;

Where a and b are in the same order of magnitude. With an unsigned type,
you must assert( a >= b ) before doing the subtraction or result will be
wrong. You don't need to do that with signed types. Normal math, using
reasonable numbers, just works as expected.

Right. If you don't have some *very* specific requirements, an int
will do.

The way I see it, it's much like the question "which container should I
use?" The standard tells you to use a vector unless you have a specific
need that it doesn't address. (Like for example profiling has shown that
deque would be faster, or you need the iterators to stay valid after
insertion/removal of elements.)
And who says that speed is important here? Or space? :)

Well if either speed or space were important, the OP wouldn't need our
answer, he could simply measure the code with type A and type B and see
which type is better.

This means that the important consideration is readability, and
idiomatic correctness... When these considerations are taken into
account, which type is better for holding an integer, char or int? To
me, the answer is obvious.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,021
Latest member
AkilahJaim

Latest Threads

Top