2010-04-20 7 views
11

Esta mañana encontramos un antiguo fragmento de código que causaba que una llamada a la biblioteca se bloqueara.Alguien está usando el nombre de la estructura como un nombre de variable también. ¿Qué dice realmente el código?

struct fred 
{ 
    int  a; 
    int  b; 
    int  c; 
}; 

fred  fred[MAX_SIZE+1]; 

memset(fred, 0, sizeof(fred) * MAX_SIZE+1); 

Parece ser que el sizeof (Fred) puede haber sido el tamaño de la matriz completa, más que el tamaño de la estructura, ya que se sobrescribe una gran cantidad de la memoria.

El hecho de que compilara sin previo aviso en varios sistemas diferentes parecía extraño.

¿Existe una semántica correcta para este caso en el que el tipo y el nombre de la variable están colisionando? o es este un tipo de comportamiento indefinido? o solo un defecto?

+3

** ¿Qué dice realmente el código? ** Dice que alguien en su organización necesita hablar con severidad. ¿Quién pensó que sería una buena idea? – rlbond

+1

@rlbond - El codificador se ha ido hace mucho, pero su memoria persiste. – EvilTeach

+4

Me parece interesante que ese código malvado sería publicado por "EvilTeach" ... :) – dicroce

Respuesta

14

El número uno sería, no hagas esto, ya que es confuso, pero ya has descubierto esto.

La variable oculta el nombre de la estructura, pero aún puede usar struct fred para referirse al tipo.

p. Ej.

fred  fred[MAX_SIZE+1]; 

memset(fred, 0, sizeof(struct fred) * (MAX_SIZE+1)); 

Como alternativa, ¿por qué no utilizar el tamaño del objeto completo. De esta forma, su llamada a memset es robusta frente a cambios en el tamaño o tipo de matriz. Que puede hacer:

memset(fred, 0, sizeof fred); 

Usted necesidad tiene los paréntesis cuando se utiliza un tipo id con sizeof pero no es necesario cuando se utiliza un objeto.

2

¿No debería ser sizeof (fred) * (MAX_SIZE + 1) ya que su matriz es MAX_SIZE + 1 de largo?

+0

Sí. Eso ciertamente es mal adicional. +1 – EvilTeach

1

Cuando define la variable, oculta el nombre del tipo, entonces sí, cuando hace sizeof(fred), obtiene el tamaño de la matriz, no el tamaño de la estructura. es bastante fácil verificar esto simplemente imprimiendo sizeof(fred).

La respuesta corta, sin embargo, es simplemente: "no hagas eso".

0

Con la excepción de los casos de tamaño en tiempo de ejecución, la forma típica idiomática utilizar memset (así como memcpy, malloc, etc.) es hacer

memset(dst_ptr, 0, sizeof *dst_ptr); 

o, equivalentemente,

memset(&dst_object, 0, sizeof dst_object); 

que es como debería haber sido utilizado en este caso, así

memset(&fred, 0, sizeof fred); 

y el problema con el conflicto de nombre no surgiría. La variante memset(fred, 0, sizeof fred) también funcionará.

2

La última declaración tiene prioridad:

[C++03: 9.1/2]: una definición de clase introduce el nombre de la clase en el ámbito donde se define y se esconde ninguna clase, objeto, función, u otra declaración del mismo nombre en un ámbito de inclusión (3.3). Si se declara un nombre de clase en un ámbito donde también se declara un objeto, función o enumerador del mismo nombre, cuando ambas declaraciones están dentro del alcance, solo se puede hacer referencia a la clase utilizando un especificador de tipo elaborado (3.4.4).

Un elaborados de tipo especificador es cuando se cumple struct o class en la parte delantera del tipo; esto efectivamente lo desambigua, aunque estrictamente hablando, y debido a la regla citada anteriormente, la búsqueda nunca fue realmente ambigua en primer lugar.

Así:

void foo() 
{ 
    struct bar {}; 
    bar bar[5]; 

    memset(bar, 0, sizeof(bar)); 
    //    ^^^^^^^^^^^ 
    //     5 

    memset(bar, 0, sizeof(struct bar)); 
    //    ^^^^^^^^^^^^^^^^^^ 
    //     1 
} 

// (NB. Exact sizes may differ; 1 and 5 given as relative examples only) 

El hecho de que todo esto es bien definida es una de las razones de que no recibió una advertencia. Aún así, hubiera espero que un compilador inteligente detectaría su código como un posible error del programador — racionalizando acerca de por qué una implementación dada hace o no alguna advertencia dada en algún caso no obligatorio, sin embargo, es en gran parte una tontería.

+1

Extraño, ¿por qué esto no tiene más votos ascendentes? ¡Cita el estándar! =) –

Cuestiones relacionadas