2009-06-18 23 views
15

Cuando uso malloc y hago una manipulación de memoria similar, ¿puedo confiar en que sizeof (char) siempre es 1?¿Es necesario multiplicar por sizeof (char) al manipular la memoria?

Por ejemplo, necesito asignar memoria para N elementos del tipo char. Se multiplica por sizeof(char) necesario:

char* buffer = malloc(N * sizeof(char)); 

o puedo confiar en sizeof (char) siempre es 1 y omita la multiplicación

char* buffer = malloc(N); 

entiendo por completo que sizeof se evalúa durante la compilación y luego el compilador incluso podría compilar la multiplicación y, por lo tanto, la penalización de rendimiento será mínima y muy probablemente cero.

Estoy preguntando principalmente sobre la claridad del código y la portabilidad. ¿Es esta multiplicación alguna vez necesaria para char tipo?

Respuesta

6

Si bien no es necesario, considero una buena práctica dejar el tamaño de (char) porque hace que el código sea más legible y evita el uso de un número mágico. Además, si el código necesita ser cambiado más tarde para que en lugar de una char sea mallocing el tamaño de algo en un puntero para ese objeto, es más fácil cambiar el código que si solo tiene un "1".

+6

Este argumento de "facilidad para cambiar el código" es bull. 'sizeof()' tiene 8 caracteres.Tener que agregarlo porque alguien no escribió 'sizeof (char)' y luego el tipo cambiado a 'wchar_t' no le dará a nadie túnel carpiano, y si le preocupa esto, debería usar' sizeof * buf' de todos modos porque te ahorra incluso _less_ tipando. –

+0

@ChrisLutz, estoy viendo el estándar C11 y no veo ninguna cláusula que específicamente diga 'sizeof (char)' es una. Según [wikipedia] (http://en.wikipedia.org/wiki/C_data_types#Basic_types), puede ser cualquier cosa: _ "por ejemplo, todos los tipos pueden ser de 64 bits" _. ¿Podría decirme por favor en el estándar que dice eso? – Shahbaz

+4

@Shahbaz - 6.5.3.4 párrafo 4: "Cuando' sizeof' se aplica a un operando que tiene el tipo 'char',' unsigned char', o 'signed char', (o una versión calificada de los mismos) el resultado es 1. " Por lo tanto, siempre ha sido así, siempre lo será. El 'char' es el" byte "de C. Desde la perspectiva del lenguaje, no importa cuántos bits sea un' char', es la unidad completa más pequeña y todos los valores 'sizeof' se dan en términos de' char 's en lugar de" bytes "(que no existen correctamente en el estándar C). Si todos los tipos son de 64 bits, 'sizeof (char) == sizeof (short) == sizeof (int) == sizeof (long) == 1', no 8. –

6

No es necesario. Ver here (por ejemplo).

sizeof(char) se define por la norma C para estar siempre (byte). Tenga en cuenta que dado que sizeof devuelve un número de bytes, la cantidad de bits por byte es irrelevante (y en términos prácticos es 8 de todos modos).

14

sizeof(char) es siempre 1 independientemente del tipo de manipulación de memoria que realice. Sin embargo, sizeof(TCHAR) puede variar según las opciones de compilación.

+0

No soy un experto, pero ¿el tamaño de un personaje no aumenta en las situaciones de Unicode? –

+4

@ Shadow, no. El tipo de carácter ancho wchar_t generalmente se usa en lugar de char en ese caso. El negocio TCHAR específico de Microsoft es una forma de escribir código que se puede compilar para caracteres anchos o estrechos. No está claro si fue una buena idea o no. – RBerteig

+0

@RBerteig: Diría que está claro que es una mala idea. La única razón para usar cadenas de caracteres "no" anchas en Windows es por el hecho de tener un código portátil que funcione igual en otros sistemas que cumplen con los estándares (POSIX). Tan pronto como escriba 'TCHAR', su código ya está contaminado con cosas específicas de Windows y también podría simplemente usar sus funciones y tipos de ancho directamente. No es que nadie ** quiera ** que sus programas se rompan tan pronto como el usuario intente abrir un nombre de archivo con caracteres que no sean de página de códigos. –

27

Por definición, sizeof (char) siempre es igual a 1. Un byte es el tamaño del carácter en C, cualquiera que sea el número de bits en un byte (8 en la CPU de escritorio común).

El ejemplo típico donde un byte no es de 8 bits es el PDP-10 y otras arquitecturas antiguas similares a minitorreras con bytes de 9/36 bits. Pero bytes que no son 2^N se están convirtiendo en muy poco común que creen

Además, creo que esto es mejor estilo:

char* buf1; 
double* buf2; 

buf1 = malloc(sizeof(*buf1) * N); 
buf2 = malloc(sizeof(*buf2) * N); 

porque funciona sea cual sea el tipo de puntero es.

+0

Pensé que la definición de 1Byte = 8 bits. ¿Tienes un ejemplo donde esto no aplica? – AlexDrenea

+6

La definición de 1 byte es N bits, donde N depende de la máquina. No todas las máquinas tienen 8 bits/byte (aunque actualmente no hay muchas que no lo hagan) –

+11

@AlexDrenea: Hoy en día, normalmente encontrará solo bytes de 8 bits. Pero la definición de byte varía y no está ligada a las arquitecturas actuales, porque había sistemas con bytes de 9 bits e incluso bytes de 36 bits. Si quiere estar seguro, use el término ISO "octeto" en lugar de "byte". – OregonGhost

10

Lo considero tipo de anti-pattern. Señala que el programador no sabía exactamente qué estaba haciendo, lo que arroja el resto del código de manera dudosa.

Concedido, no es (citando Wikipedia) "ineficaz", pero sí lo encuentro "lejos de ser óptimo". No cuesta nada en tiempo de ejecución, pero desordena el código con basura innecesaria, al tiempo que indica que alguien lo consideró necesario.

Además, tenga en cuenta que la expresión no se analiza como una función-llamada: sizeof no es una función. No estás llamando a una función que le pase el símbolo mágico char.Está aplicando el operador de prefijo unario incorporado sizeof a una expresión, y su expresión es en este caso un molde para el tipo char, que en C se escribe como (char).

Es perfectamente posible, y muy recomendable siempre que sea posible, utilizar sizeof en otras expresiones, entonces se producirá el tamaño del valor de la expresión:

char a; 
printf("A char's size is %u\n", (unsigned int) sizeof a); 

Esto imprimirá 1, siempre, sobre todo conforme C implementaciones.

también en gran medida de acuerdo con David Cournapeau y considero repitiendo el nombre del tipo en un -call malloc() a también ser una especie de un anti-patrón.

En lugar de

char *str; 

str = malloc(N * sizeof (char)); 

que muchos escribiría para asignar un búfer de cadena N-personaje-capacidad, me gustaría ir con

char *str; 

str = malloc(N * sizeof *str); 

O (para cuerdas solamente) omiten el sizeof como por encima, pero esto por supuesto es más general y funciona igual de bien para cualquier tipo de puntero.

+2

No estoy de acuerdo. Si lo omite, usted (y cualquier persona que lea su código) debe recordar que este es un caso especial y reconocerlo como tal. Eso aumenta la carga cognitiva. A veces, más código es mejor. –

+1

Sí, sizeof no es una función, pero para mí es más fácil si lo tratas como tal. A menos que sepa de un caso donde los paréntesis adicionales cambian la salida? –

+2

@Michael Carman: por lo general, es un caso especial, porque a menudo asigna y trabaja con cadenas, mientras que si crea una matriz de entradas, puede ser para cualquier propósito. Necesitamos tratar las cadenas de forma diferente que las matrices de tipo arbitrario, y encuentro que la falta de 'sizeof (type)' en un 'malloc()' es un buen recordatorio de esto. –

-4

El uso de sizeof (char) hace que su código sea más legible y portátil.

En x86, todos sabemos que un carácter es de 1 byte. Pero escribirlo explícitamente ayuda a aclarar tus intenciones, lo que siempre es bueno.

Además, ¿qué pasa si su código se pone en alguna otra plataforma donde un personaje no es de 1 byte. ¿Qué pasaría si un personaje tuviera solo 4 bits?

De acuerdo, no es necesario, pero no ralentiza el tiempo de ejecución y valdrá la pena en ese caso raro que necesita para portar su código a una arquitectura diferente.

+0

Eso es lo que estaba preguntando. Oficialmente char es el trozo de memoria más pequeño que no se garantiza que sea de 8 bits. La pregunta es si el malloc y todas las demás cosas similares funcionan en términos de caracteres, no bytes de 8 bits. – sharptooth

+1

Ahh vale, entonces sí, malloc funciona en términos de caracteres, no de bytes. malloc (1) devolverá 1 bloque de tamaño de caracteres de memoria. – samoz

+2

-1 su respuesta es objetivamente incorrecta. 'sizeof (char)' is _always_ 1. Si un 'char' es solo 4 bits, entonces 4 bits es 1 byte en esa plataforma, pero' sizeof (char) 'se define como 1 (byte), sin importar cuántos bits es. El problema que discute se aborda mediante la macro 'CHAR_BITS'. –

3

Otra cosa a tener en cuenta es que el compilador sabe estáticamente que el valor de sizeof (char) es 1 y también sabe que multiplicar un número por un static 1 implica que la multiplicación no necesita hacerse; el compilador lo optimizará. Las preocupaciones sobre el rendimiento no deberían entrar en consideración por estos motivos.

3

De "Nuevo estándar C. Un comentario económico y cultural".

  1. Estadísticas: 2,0% de sizeof se toman de char y 1.5% - de unsigned char. Página 1033 en la versión 1.2 del libro.
  2. página 1037.

El número de bits en la representación de un tipo de carácter es irrelevante.Por definición, el número de bytes en byte un tipo de carácter es uno.

Directrices de codificación Los desarrolladores a veces asocian un byte como siempre que contiene ocho bits. En hosts donde el tipo de carácter es de 16 bits, esto puede llevar a a la suposición incorrecta de que aplicando sizeof a un tipo de caracteres devolverá el valor 2. Estos problemas se discuten en otra parte.