2010-02-06 31 views
5

¿Es segura la siguiente conversión?Conversión insegura

int b[10][10]; 
char *x; 
int a[]={0,1,2,3,4,5,6,7,8,9}; 

for(int i=0;i<10;i++) 
    for(int j=0;j<10;j++) 
    b[i][j]=a[i]; 

for(x=(char *)&b[0];x<=(char *)&b[9][9];x+=sizeof(a+1)) // Problem lies here! 
    printf("%d\n",*x); 

no creo que la conversión anterior en el bucle for es seguro (creo que es dependiente de la plataforma). Por favor, corríjame si estoy equivocado. Estoy sorprendido porque el código se compila sin dar ninguna advertencia, incluso cuando se compila utilizando las opciones -Wall -pedantic en gcc.

+0

¿Qué es 'a', en' a + 1'? – GManNickG

+0

Supuse que era un error b. Sin embargo, podría estar equivocado ... – Pod

+0

@GMan y @Pod: ¡Editado! –

Respuesta

7

Todo esto tiene la posibilidad de ser legal por una y única razón: el objeto de matriz 2D int se reinterpreta como una matriz de objetos char. Si bien, en general, la reinterpretación de la memoria conduce a un comportamiento indefinido, la especificación del lenguaje permite explícitamente las reinterpretaciones "array of [signed/unsigned] char" para objetos de cualquier tipo.

Sin embargo, un problema formal de la seguridad sigue estando ahí. El idioma no garantiza que ningún patrón de bits tenga un valor válido del tipo char. Su intento de leer la memoria reinterpretada a través del tipo char teóricamente puede causar un comportamiento indefinido si encuentra una representación de captura para char. Para estar seguro, debe utilizar el tipo unsigned char, que es el único tipo que no tiene representaciones de trampas. Por supuesto, una plataforma con una captura char se puede llamar con seguridad "exótica".

Mientras tanto, su sizeof(a + 1) no parece tener ningún sentido. a + 1 es una expresión del tipo int *. No está claro por qué querría usar el tamaño del puntero para incrementar su valor de x en este caso. ¿Qué estabas tratando de lograr?

En cuanto a la ausencia de advertencias ... yo no esperaría que el compilador emitió ningún aviso aquí. GCC a menudo advierte sobre el tipo de juego de palabras (también conocido como reinterpretación de memoria), pero desde char las reinterpretaciones están explícitamente permitidas (como dije antes), no hay ninguna advertencia aquí. Además, los moldes explícitos generalmente tienden a suprimir las advertencias, ya que son una forma de decirle al compilador que realmente desea hacer algo, independientemente de lo equivocado y/o peligroso que sea.

+0

@Andrey T: _a + 1 es una expresión de int * type_ Y eso es lo que quiero. Es un rompecabezas de una competencia de codificación en línea. –

+1

@Prasoon: Por cierto, su ciclo se ve, espero que uno use 'sizeof (int)' aquí, como 'sizeof (a [1])' o 'sizeof (* (a + 1))' o ' sizeof (* a) '. En cuanto a 'sizeof (a + 1)', de nuevo, no entiendo cuál es el objetivo de esto. No tiene sentido para mí. – AnT

+0

He asumido que sizeof (int) y sizeof (int *) son los mismos en esa plataforma en particular. Sí, creo que sizeof (* a) parece más correcto. –

1

un elenco de cualquier tipo de puntero a char * se permite explícitamente por el lenguaje C. así que la mayor parte de esto está bien.

for(x=(char *)&b[0]; x <= (char *)&b[9][9]; x += sizeof(a+1)) 

La primera parte está bien x = (char*)&b[0]; establece un puntero char al comienzo de la matriz. La prueba también es correcta x <= (char *)&b[9][9] será verdadera siempre que x puntos dentro de la matriz.

x += sizeof(a+1) es la parte dudoso. En la mayoría de sizeof arquitecturas de CPU de 32 bits (int *) acaba pasa a ser el mismo que sizeof (int), por lo que este código será probablemente trabajo, pero sólo por accidente.

Estoy seguro de lo que se pretendía era x += sizeof(a[0]) o x += sizeof(b[0]), pero dado que el código realmente hizo lo que se pretendía, nadie notó el error.

Cuestiones relacionadas