2009-11-15 45 views
13

Estoy tratando de entender las diferencias entre C y C++ con respecto a punteros void. las siguientes compila en C, pero no C++ (todas las compilaciones de hecho con gcc/g ++ -ansi -pedantic -Wall):punteros void: diferencia entre C y C++

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

porque malloc rendimientos void*, que C++ no permite asignar a int* mientras que C no permite ese.

Sin embargo, aquí:

void foo(void* vptr) 
{ 
} 

int main() 
{ 
    int* p = (int*) malloc(sizeof(int)); 
    foo(p); 
    return 0; 
} 

Tanto C++ y C compilarlo con ninguna queja. ¿Por qué?

K & R2 decir:

Cualquier puntero a un objeto puede ser convertir al tipo void * sin pérdida de información. Si el resultado es convierte de nuevo a la original tipo de puntero, el puntero original es recuperado.

Y esta bonita suma todo lo que hay acerca de void* conversiones en C. ¿Qué es lo que dicta el estándar C++?

+0

GMan explica correctamente por qué recibe el error. Dicho esto, si está escribiendo código C++, debe usar nuevo/nuevo [] y eliminar/eliminar [] en lugar de malloc/calloc y libre/libre. –

Respuesta

31

En C, las conversiones puntero hacia y desde void* eran siempre implícita.

En C++, las conversiones de T* a void* son implícitas, pero void* a cualquier otra cosa requiere un lanzamiento.

+1

puede dar una fuente para su segunda declaración? está escrito en C++ estándar? – zaharpopov

+6

No hay mucho que citar, realmente. Está en la sección 4.10.2.Más o menos dice que 'T *' se puede convertir a 'void *'. Deja fuera el reverso, lo que implica que debes usar un yeso. – GManNickG

+0

@zaharpopov: mirar hacia arriba reinterpret_cast <> o static_cast <> –

6

C++ es más-fuertemente tipado de C. Muchas conversiones, especialmente aquellas que implican una interpretación diferente del valor, requiere una conversión explícita. El operador new en C++ es una forma segura de tipo para asignar memoria en el montón, sin un molde explícito.

0

Es útil entender que las conversiones de tipos de puntero en realidad no requieren la ejecución de instrucciones de CPU adicionales. Se analizan durante el tiempo de compilación para comprender las intenciones del desarrollador. void * es un puntero opaco. Todo dice que el tipo de objeto puntiagudo es desconocido. C está débilmente tipado. Permite la conversión directa entre (void *) y cualquiera (T*) implícitamente. C++ está fuertemente tipado. Una conversión de (void *) a (T*) no sería un buen argumento para un lenguaje fuertemente tipado. Pero C++ tenía que permanecer compatible con C, por lo tanto, tenía que permitir tales conversiones. El principio rector es: lo explícito es mejor que lo implícito. Por lo tanto, si desea convertir un (void*) a algún puntero específico (T*), debe escribirlo explícitamente en el código. La conversión de (T*) a (void*) no requiere conversión explícita, ya no hay nada mucho que se puede hacer en un (void *) puntero directamente (se puede llamar libre de() sin embargo). Por lo tanto, (T*) a (void*) la conversión es bastante segura.

+1

Si las conversiones de puntero requieren instrucciones de CPU o no es un detalle de implementación. No hay absolutamente nada en los lenguajes C y C++ que requiera que estas conversiones sean puramente conceptuales (es decir, no requieren instrucciones de la CPU). Por el contrario, ambos lenguajes están formulados específicamente para permitir diferentes representaciones para diferentes tipos de punteros. Mientras que "entender" que en el caso típico la conversión realmente no hace nada en el nivel de la CPU podría ser útil, escribir un código C o C++ que se base en esa suposición es un error grave. – AnT

+1

... Y no entiendo el punto sobre "permanecer compatible con versiones anteriores". C++ requiere un molde explícito para convertir de 'void *'. Que ya cuenta no es compatible hacia atrás con C. – AnT

+0

C++ no es totalmente compatible con C. Simplemente proporciona maneras de hacer la migración tan fácil como sea posible siempre que sea necesario. Al pasar de ser débilmente tipeado a fuertemente tipado, se producen problemas de compatibilidad. C++ simplemente trata de proporcionar formas simples (como hacer un lanzamiento de tipo explícito en un puntero de vacío) para facilitar la migración. –