2009-11-03 11 views
58

¿Qué arrojaría esta afirmación?¿Cuál es el tamaño del vacío?

void * p = (void*) malloc(sizeof(void)); 

Editar: Una extensión a la pregunta.

Si sizeof (void) produce 1 en el compilador GCC, se asigna 1 byte de memoria y el puntero p apunta a ese byte y p ++ se incrementará a 0x2346? Supongamos que p fuera 0x2345. Estoy hablando de p y no * p.

+3

FYI. Esto no es estándar C. En muchos compiladores, esto sería un error en tiempo de compilación. –

+0

¿por qué necesita saberlo? Comprender esto puede ayudarnos a responder la pregunta. –

+2

Comentando su edición: sí, en GCC (solamente), al incrementar un puntero de vacío se agrega uno al valor. Si valora la portabilidad de su código, no abuse de la libertad que GCC le brinda. Es completamente no estándar. Y GCC admite tanto con '-std = c99 -pedantic'. –

Respuesta

42

El tipo void no tiene talla; eso sería un error de compilación. Por la misma razón, no puede hacer algo como:

void n; 

EDITAR. Para mi sorpresa, haciendo sizeof(void) realidad qué compilar el GNU C:

$ echo 'int main() { printf("%d", sizeof(void)); }' | gcc -xc -w - && ./a.out 
1 

Sin embargo, en C++ no es así:

$ echo 'int main() { printf("%d", sizeof(void)); }' | gcc -xc++ -w - && ./a.out 
<stdin>: In function 'int main()': 
<stdin>:1: error: invalid application of 'sizeof' to a void type 
<stdin>:1: error: 'printf' was not declared in this scope 
+23

Pero GCC tiene una opción para tratar 'sizeof (void) == sizeof (char)' ... Ver -Wpointer-arith –

+2

@Jon esto es para tontos de principios de los 80 que recién comenzaban a aprender a programar. Los estándares no fueron ampliamente decididos. – unixman83

+3

¿Por qué es esta la respuesta aceptada? – michaelsnowden

3

En C, sizeof(void) == 1 en GCC, pero esto parece depender en tu compilador

En C++, me sale:

 
In function 'int main()': 
Line 2: error: invalid application of 'sizeof' to a void type 
compilation terminated due to -Wfatal-errors. 
+3

Solo en GCC es sizeof (void) == 1; en el estándar, es un comportamiento indefinido. –

+0

Actualizado para agregar una nota específica de GCC. –

+0

@JonathanLeffler: No es un comportamiento meramente indefinido. Es una violación de restricción. N1570 6.5.3.4p1. –

15

Aunque void puede estar en el lugar para un tipo, que en realidad no puede contener un valor. Por lo tanto, no tiene ningún tamaño en la memoria. Obtener el tamaño de void no está definido.

Un void puntero es simplemente una construcción del lenguaje significa un puntero a sin tipo de memoria.

+1

¿y qué? No debería ninguna estructura vacía tampoco consumir ningún tamaño en la memoria y eso debería ser un problema. Bueno, en realidad, me pregunto si las estructuras vacías realmente están usando 0 bytes en C++ (como ocurre en C) parece que sizeof devuelve 1 para ellos. – kriss

+1

@kriss No estoy seguro de lo que dices, pero como te has dado cuenta, las estructuras vacías * do * ocupan memoria por razones de identidad del objeto. –

+1

de hecho, pero no era cierto en C y el uso de la memoria para objetos vacíos se siente mal. – kriss

5

sizeof() no se puede aplicar a tipos incompletos. Y void es un tipo incompleto que no se puede completar.

34

Si está utilizando GCC y no está utilizando los indicadores de compilación que eliminan las extensiones específicas del compilador, entonces sizeof(void) es 1. GCC tiene un nonstandard extension que hace eso.

En general, void es un tipo incompleto, y no se puede usar sizeof para tipos incompletos.

+2

La opción '-Wpointer-arith' está implícita en' -pedantic'. Siempre utilicé '-pedantic'. :) –

+1

@jleedev De hecho, también uso -pedante tanto como puedo. Desafortunadamente, sin embargo, algunos encabezados de biblioteca de terceros hacen que gcc -pedantic sea muy triste :( – hrnt

+1

+1 Realmente, ¿por qué GCC tiene miles de extensiones inútiles? –

0

A la segunda parte de la pregunta: Tenga en cuenta que sizeof (void *)! = Sizeof (void). En un arco de 32 bits, sizeof (void *) tiene 4 bytes, por lo que p ++ se establecerá en consecuencia. La cantidad en que se incrementa un puntero depende de los datos a los que apunta. Por lo tanto, se incrementará en 1 byte.

+1

por lo que p apuntaba a datos de 1 byte, ya que sizeof (void) da 1, así p ++ significa que p sería incrementado en 1 y no en 4 ?? – Lakshmi

+1

La cantidad en que se incrementa un puntero depende de los datos que apunta hacia. Así que sí. –

+0

p es de tipo void * (void pointer), no está vacío. Por lo tanto, se incrementaría por el tamaño del tipo void * (que generalmente es 4 en sistemas de 32 bits). – Technowise

-1

mientras sizeof (void) quizás no tenga sentido en sí mismo, es importante cuando está haciendo cualquier cálculo de puntero.

por ejemplo.

void *p; 
while(...) 
     p++; 

Si sizeof (void) se considera 1, entonces esto funcionará. Si sizeof (void) se considera 0, se golpea un ciclo infinito.

+2

El fragmento de código de ejemplo es ilegal en C y C++. Algunos compiladores lo permiten de todos modos. –

+0

No, no es importante en absoluto (aunque los autores de gcc aparentemente pensaron que era). Si quiere hacer una aritmética de punteros en punteros de bytes, use 'unsigned char *'. –

-1

La mayoría de los compiladores de C++ eligieron generar un error de compilación al intentar obtener sizeof(void).

Al compilar C, gcc no se ajusta y eligió definir sizeof(void) como 1. Puede parecer extraño, pero tiene un fundamento. Cuando se realiza una aritmética de puntero, agregar o eliminar una unidad significa agregar o eliminar el objeto que apunta al tamaño. Por lo tanto, la definición de sizeof(void) como 1 ayuda a definir void* como un puntero a byte (dirección de memoria sin tipo). De lo contrario, tendría comportamientos sorprendentes utilizando la aritmética del puntero como p+1 == p when p es void*. Tal aritmética de puntero en punteros vacíos no está permitida en C++, pero funciona bien al compilar C con gcc.

La manera estándar recomendada sería usar char* para ese tipo de propósito (puntero a byte).

Otra diferencia similar entre C y C++ al utilizar sizeof se produce cuando se definió una estructura vacía como:

struct Empty { 
} empty; 

con gcc como mi compilador de C sizeof(empty) vuelve 0. Con g ++ el mismo código devolverá 1.

No estoy seguro de qué establece los estándares C y C++ en este punto, pero creo que definir el tamaño de algunas estructuras/objetos vacíos ayuda con la administración de referencias para evitar esas dos referencias a diferentes objetos consecutivos, siendo el primero vacío, obtener la misma dirección. Si la referencia se implementa utilizando punteros ocultos como se hace a menudo, garantizar una dirección diferente ayudará a compararlos.

Pero esto es simplemente evitar un comportamiento sorprendente (comparación de casos de esquina de las referencias) mediante la introducción de otro (objetos vacíos, incluso los POD consumen al menos 1 byte de memoria).

+3

"C eligió definir sizeof (void) como 1." - No, eso está mal. 'sizeof (void)' no está definido en C, igual que en C++.GCC simplemente no se está conformando en este punto, y la aritmética del puntero en punteros 'void' simplemente no está definida tampoco -' void * p; p ++; 'no es válido. Incluso GCC le dará una advertencia al compilar con el indicador '-pedantic'. Y también está equivocado sobre el comportamiento predeterminado de GCC para C++: por defecto * esto se trata como un error *. –

+0

@Konrad: sí, estoy bastante seguro de que no era cierto con la versión anterior de gcc, pero los actualizados funcionan como usted dice. – kriss

+0

Al menos en C, una definición 'struct' vacía es un error de sintaxis; El soporte de gcc es una extensión. Pueden ser válidos en C++; No estoy seguro. –

6

void no tiene tamaño. Tanto en C como en C++, la expresión sizeof (void) no es válida.

En C, citando N1570 6.5.3.4 párrafo 1:

El operador sizeof no se aplicará a una expresión que tiene función de tipo o un tipo incompleto, al nombre entre paréntesis de tal tipo, o a una expresión que designa un miembro de campo de bit.

(N1570 es un proyecto de la norma ISO 2011 C).

void es un tipo incompleto. Este párrafo es una restricción de , lo que significa que cualquier compilador de C conforme debe diagnosticar cualquier violación de la misma. (El mensaje de diagnóstico puede ser una advertencia no fatal.)

El estándar C++ 11 tiene fraseología muy similar. Ambas ediciones se publicaron después de que se hizo esta pregunta, pero las reglas se remontan al estándar ANSI C de 1989 y a los estándares más antiguos de C++. De hecho, la regla de que void es un tipo incompleto al que sizeof no pueden ser aplicadas se remonta exactamente en cuanto a la introducción de void a la lengua.

gcc tiene una extensión que trata sizeof (void) como 1. gcc no es un compilador C conformando de forma predeterminada, por lo que en su modo predeterminado que no advierte de la sizeof (void). Extensiones como esta están permitidas incluso para compiladores de C totalmente conformes, pero el diagnóstico aún es necesario.

+0

Supongo que permitieron 'sizeof (void) == 1' por coherencia con la aritmética del puntero en el puntero' void', que también es una [extensión gcc] (https://gcc.gnu.org/onlinedocs/gcc/Pointer -Arith.html # Pointer-Arith). Citando de su documentación: 'Una consecuencia de esto es que sizeof también se permite en vacío y en tipos de función, y devuelve 1.'. Pero el mensaje de diagnóstico debe estar presente por defecto para C, como lo requiere el estándar. –

+0

@GrzegorzSzpetkowski: (Respondiendo un par de años más tarde.) Sí, el estándar requiere un diagnóstico, pero gcc no es un compilador de C conforme por defecto. Lógicamente, el estándar C no impone requisitos en implementaciones que no pretenden ajustarse a él. Se puede hacer que gcc (casi) se ajuste a las opciones correctas de la línea de comandos, como '-std = c11 -pedantic'. Con tales opciones, emite el diagnóstico requerido. –

Cuestiones relacionadas