0

I often use smaller data types in structs/classes when it is needed in memory savings. I also use them in network/disk IO.

My question is if intermediate code that use those objects with smaller data types, should be of the same type, or just plain types like int and cut them when storing. For example:

struct Object
{
  int16 health;
  int8 mana;
};

void function(int16 health, int8 mana)
{
  Object object;
  object.health = health;
  object.mana = mana;
}

or

void function(int health, int mana)
{
  Object object;
  object.health = static_cast<int16>(health); // Cutting int
  object.mana = static_cast<int8>(mana); // Cutting int
}
4
  • 4
    I'm not sure how you can make sense of your second example. What's supposed to happen if health > MAX_OF_INT16? Is this impossible? Then make health an int16. Do you want to truncate the value? Then make it explicit. The second code just screams "I don't know what I'm doing". May 31, 2016 at 16:16
  • Some people use just plain int, even when its impossible for variable to have negative value, or value that high. And I would use int also as default. Im truncating it only when saving it to object member, only for purpose of memory saving.
    – John Lock
    May 31, 2016 at 16:31
  • 1
    It is still a very surprising behaviour. If I see a function that accepts an int, then I assume I can safely pass it an int. Your function would just do a half-assed attempt to cast it to the correct type, and it would most likely return garbage for anything not in the range of an int16 or int8. I don't see any upside for your second code. May 31, 2016 at 16:34
  • This question addresses another issue with the code, passing around data members not wrapped in their object: Do you generally send objects or their member variables into functions?
    – user22815
    Jun 1, 2016 at 5:04

1 Answer 1

6

You're asking the wrong question.

The right question is "who should be responsible for ensuring that the desired values are within the limitations required by the data type?"

Let's look at your cases:

void function1(int16_t health, int8_t mana)
{
  Object object;
  object.health = health;
  object.mana = mana;
}

void function2(int health, int mana)
{
  Object object;
  object.health = static_cast<int16_t>(health); // Cutting int
  object.mana = static_cast<int8_t>(mana); // Cutting int
}

The interface of function1 has an explicit size requirement on its types. It is therefore the responsibility of everyone who calls that function to verify that the values that they want to store fit within the sizes specified in the interface.

function2 by contrast has an implicit size requirement. It says that it takes ints. But it doesn't really; if you pass it values outside of the size of the data type, then it invokes implementation-defined behavior.

In some respects, function1 is better. The sizes for the parameters are explicitly stated. But because of C++'s conversion rules, something as obviously broken as this won't cause even a compile error:

function1(0xFFFFFFF, 23);

That is a narrowing conversion, which is allowed. It invokes implementation-defined behavior, which is probably not what you want.

Thus, the real question is... what do you want?

If the user wants to set the health to more than 0x7FFF, what should your code do? Should it silently accept it and invoke implementation-defined behavior? Or should it provoke an error condition, throw an exception or just flat-out terminate?

If you want to do any of the latter, then you must use function2 (or rather, an error-checking version of function2). By using it, the implicit interface requirement can at least be verified. This makes it possible to track down code that wants to set the value improperly.

1
  • 2
    In my experience "Should it silently accept it and invoke implementation-defined behavior?" is almost always wrong. "Or should it provoke an error condition, throw an exception or just flat-out terminate?" is almost always right. That being said, every situation should be judged on its own merits. +1
    – Mike
    May 31, 2016 at 20:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.