Tamaño “C” con un tipo o variable

Recientemente vimos a alguien recomendar a otro usuario el uso de sizeof var en lugar de sizeof (type). Siempre pensé que era solo una elección de estilo. ¿Hay alguna diferencia significativa? Como ejemplo, las líneas con f y ff se consideraron mejores que las líneas con g y gg:

typedef struct _foo {} foo; foo *f = malloc(count * sizeof f); foo *g = malloc(sizeof(foo) * count); foo **ff = malloc(count * sizeof *ff); foo **gg = malloc(sizeof(foo*) * count); 

En mi opinión, el primer set es solo una cuestión de estilo. Pero en el segundo par de líneas, el segundo * adicional puede confundirse fácilmente para una multiplicación.

Si se cambia el tipo de variable, no será necesario cambiar el tamaño si la variable es el argumento, en lugar del tipo.

Con respecto al comentario de @ icepack: la posibilidad o probabilidad de cambio para el nombre de tipo vs. variable no es el problema. Imagine que el nombre de la variable se usa como argumento para sizeof y luego se cambia. En el mejor de los casos, una operación refactor-rename cambia todas las ocurrencias y no se introduce ningún error. En el peor de los casos, se omite una instancia de un sizeof y el comstackdor se queja y usted lo soluciona. Si se cambia el tipo, está listo, no hay posibilidad de errores en el tamaño de las instrucciones.

Ahora imagine que el tipo es el argumento de sizeof. Si se cambia el tipo de variable, no hay otro medio que no sea la inspección para encontrar todos los tamaños relacionados con esa variable. Puede buscar, pero obtendrá visitas para todos los usos no relacionados de sizeof del mismo tipo. Si se pierde uno, tendrá un problema de tiempo de ejecución debido a una discrepancia de tamaño, que es mucho más difícil de encontrar.

Además de lo que dice Steve, permítanme agregar que sizeof no evalúa su operando. Entonces eres libre de hacer cualquier cosa en eso. No solo puede usar variables aún no inicializadas, sino que puede desreferenciar un puntero nulo, invocar funciones no definidas pero solo declaradas y hacer cualquier otro tipo de cosas. Te animo a usar siempre la versión de expresión por razones que Steve explicó en gran medida.

También tenga en cuenta que a veces los nombres tipo son muy largos e ilegibles, solo piense en punteros a funciones (especialmente en C ++). En lugar de escribir sizeof(my_long_type) simplemente haces sizeof t .

Puede ver poca diferencia entre estos:

 foo **ff = malloc(count * sizeof *ff); foo **gg = malloc(sizeof(foo*) * count); 

… pero ¿qué pasa si la asignación no está cerca de la statement? Si encuentro una línea como esta:

 ff = realloc(ff, count * sizeof *ff); 

entonces estoy razonablemente seguro de que la línea es correcta, sin siquiera recordar el tipo de ff . Sin embargo, si veo esto:

 ff = realloc(ff, count * sizeof(foo *)); 

entonces podría ser algo sospechoso, y necesito buscar el tipo de ff para tranquilizarme.

Las líneas f y ff son definitivamente peores que g y gg. sizeof f es el tamaño del puntero, ya que f es un punto. Para hacerlos equivalentes, tendrías que escribir sizeof *f (o, para una mejor legibilidad, sizeof(*f) ).

Tiendo a usar sizeof(type) en la asignación de memoria, pero invariablemente sizeof(variable) cuando uso una variable local o global. Sin embargo, hay sabiduría en el consejo de usar el nombre de la variable todo el tiempo.

También tuve una larga discusión (bastante animada a veces, y duró varios días, terminamos de acuerdo en diferir sobre el tema) sobre si está bien usar sizeof(variable) o si debe ser sizeof variable ; es decir, ¿importa si los paréntesis encierran el argumento a sizeof ? Nunca me he encontrado con un comstackdor que tenga información sobre sizeof(variable) , por lo que opto por la uniformidad y siempre uso los paréntesis con sizeof . Mi colega también insistió en que los paréntesis no deben usarse con variables; que de alguna manera hay / hay una distinción valiosa entre la notación con y sin paréntesis. No he sido persuadido, no espero ser persuadido.

En una táctica completamente diferente, un par de otros puntos sobre sizeof :

  • Si está utilizando C99 y VLA – arrays de longitud variable – entonces sizeof(vla) no es una constante de tiempo de comstackción. ¡Tener cuidado!
  • El preprocesador C no entiende el sizeof cual es molesto, pero lógico.

Tomar el tamaño de una variable puede tener resultados inesperados. Cuando la variable es una matriz, sizeof (array) devolverá el tamaño de la matriz, no el tamaño de un elemento individual o el tamaño de un puntero. Tomar el tamaño de un puntero devolverá el tamaño de un puntero. Pero dado que las matrices generalmente se representan como punteros cuando se pasan, las cosas pueden ser confusas.

La lógica de negocios define tu elección.

  1. Si su código se refiere a una variable en particular y sin esta variable su código no tiene sentido, elija sizeof(var)

  2. Si su código trata de un conjunto de variables con un tipo particular, elija sizeof(type) . Normalmente necesita esto si tiene un typedef que define muchas variables que procesa de manera diferente según su tipo (por ejemplo, serialización). Es posible que no sepa cuáles de estas variables permanecerán en futuras versiones de código, por lo que elegir el tipo como argumento es lógicamente correcto. Incluso el cambio de dicho tipo no afectará su sizeof línea.