I’ve seen two styles of using sizeof
for memory-related operations (such as in memset
or malloc
):
sizeof(type)
, andsizeof variable
orsizeof(variable)
Which one would you prefer, or would you use a mix of the two styles, and when would you use each style? What are the pros and cons of each style and when you use them?
As an example, I can see the following pair of situations where one style helps and the other doesn’t:
When you get the pointer indirection wrong:
type *var;
...
memset(var, 0, sizeof var); /* oops */
When the type changes:
new_type var; /* changed from old_type to new_type */
...
memset(&var, 0, sizeof(old_type)); /* oops */
I perfer sizeof(variable)
over sizeof(type)
. Consider:
int a1;
float a2;
memset(&a1,0,sizeof(a1));
memset(&a2,0,sizeof(a2));
vs.
int a1;
float a2;
memset(&a1,0,sizeof(int));
memset(&a2,0,sizeof(float));
In the first case, it’s easy to verify that the right sizes are being passed to memset
. In the second case, you need to constantly review top and bottom sections to make sure you are consistent.
3
The preference (as always) is to reflect your intention as directly as possible.
Is the intention to operate against an existing variable’s memory? If so, then use sizeof(variable)
, as this shows as closely as possible that it’s the variable itself’s memory that you care about.
Is the intention to perform some calculation on the type, for example to determine how much memory should be allocated for a new instance? If so, then use sizeof(type)
.
That is, I prefer
struct foo *bar;
bar = (struct foo *) malloc(sizeof(struct foo));
over
bar = (struct foo *) malloc(sizeof(*bar));
as the latter case looks like you’re trying to access a variable that doesn’t exist, yet.
On the other hand, I prefer
char Buffer[256];
memset(Buffer, 0, sizeof(Buffer));
over
char Buffer[256];
memset(Buffer, 0, 256 * sizeof(char));
as the intention is clearly to zero-fill the contents of the variable, so it’s the variable we should operate against. Trying to use the type metadata just confuses things, here.
2
I would vastly prefer sizeof(type)
over sizeof variable
. Even though it forces you to worry more about the type and make more changes, it helps you avoid pointer indirection mistakes, which rank among the most common cause of bugs in C.
I would not worry so much about bugs where the type in sizeof(type)
gets changed; whenever you change the type of a variable, you should do a quick scan to see where that variable is used and if you need to change any sizeof(type)
statements. Even though there is always a chance of getting this wrong, it has a much lower risk than pointer indirection mistakes.
One advantage of sizeof variable
is for arrays, but in practice I’ve found that passing arrays as pairs of first/len is much more common (in which case just use the length), plus it is also very easy to get the size wrong due to array/pointer decay, as in this example:
ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
memcpy( mat, src, sizeof( src ) ); /* NOT the same as 3*3*sizeof(float) */
}
4
The aim is to remove redundancy. If you use sizeof for an operation related to a variable, then obviously you shall reflect that in the sizeof. Yes, you can mess up like in the first example, but the cure is not use type, but *var, correctly matching the aim.
To mitigate such problems it’s usual to use macros, templates and similar tools trained for the use case rather than naked sizeof.
See my CLEAR macro that is used exclusively instead of naked memset. Saved my ass several times in cases of indirection typo or when a struct content picked up a vector or string…
4
Business logic defines your choice.
-
If your code refers to a particular variable and without this variable your code makes no sense – choose
sizeof(var)
-
If you code deals with a set of variables with particular type – choose
sizeof(type)
. Usually you need this if you have atypedef
which defines many variables which you process differently based on their type (e.g. serialization). You may not know which of these variables will remain in future code versions so choosing type as an argument is logically correct. Even changing of suchtypedef
will not affect your sizeof line.
Depending on the purpose sizeof(variable) could be the best solution. In that way, you can change your variable type if necessary, without correcting all entries for the type. But again, it depends on your objective.