¿Qué es exactamente el peligro de usar los valores de depuración de magia (como 0xLOQUESEA) como literales?

StackOverflow https://stackoverflow.com/questions/1681144

Pregunta

No hace falta decir que el uso modificable, hexagonales punteros literal es un desastre:

int *i = 0xDEADBEEF;
// god knows if that location is available

Sin embargo, ¿qué es exactamente el peligro en el uso de literales hexagonales tan variables Los valores

int i = 0xDEADBEEF;
// what can go wrong?

Si estos valores son de hecho "peligroso" debido a sus href="http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Magic_debug_values" en varios depuración escenarios, entonces esto significa que incluso si yo no uso estos literales, cualquier programa que durante el tiempo de ejecución pasa a toparse con uno de estos valores se puede bloquear.

A alguien para explicar los peligros reales de uso de literales hexagonales?


Editar sólo para aclarar, no me refiero a la utilización general de las constantes en el código fuente. Estoy hablando específicamente acerca de los problemas depuración en escenarios que puedan surgir con el uso de valores hexadecimales, con el ejemplo específico de 0xDEADBEEF.

¿Fue útil?

Solución

Creo que la preocupación suscitada en la dirección IP de formatear pregunta el día de hoy no se relaciona con el uso de literales hexagonales en general, pero el uso específico de 0xLOQUESEA. Al menos, esa es la forma en que lo leí.

Hay una preocupación con el uso de 0xLOQUESEA en particular, aunque en mi opinión, es una pequeña. El problema es que muchos depuradores y sistemas de tiempo de ejecución ya han cooptado este valor particular como un valor de marcador para indicar el montón no asignado, malos indicadores en la pila, etc.

No recuerdo de la parte superior de mi cabeza, justo la que los sistemas de depuración y de tiempo de ejecución utilizan este valor particular, pero he visto que se usa de esta manera varias veces a lo largo de los años. Si está depurando en uno de estos entornos, la existencia de la constante 0xLOQUESEA en su código será indistinguible de los valores en la memoria RAM no asignado o lo que sea, por lo que en el mejor de usted no tendrá que tan útil RAM vertederos, y en el peor obtendrá advertencias desde el depurador.

De todos modos, eso es lo que creo que el autor del comentario original, quería decir cuando le dijo que era malo para "uso en diversos escenarios de depuración."

Otros consejos

Ya no hay peligro en el uso de un hex literal que cualquier otro tipo de literal.

Si la sesión de depuración termina la ejecución de los datos como código sin que tengan la intención de, estás en un mundo de dolor de todos modos.

Por supuesto, está el "valor mágico" normal vs "bien llamada constante" problema de código olor / limpieza, pero eso no es realmente el tipo de peligro que creo que estás hablando.

Con pocas excepciones, nada es "constante".

Nosotros preferimos llamarlos "variables lentas" -. Su valor cambia tan lentamente que no nos importa volver a compilar para cambiarlos

Sin embargo, no quiero tener muchos casos de 0x07 a lo largo de una aplicación o un script de prueba, donde cada instancia tiene un significado diferente.

Queremos poner una etiqueta en cada constante que lo hace totalmente inequívoca lo que significa.

if( x == 7 )

¿Qué significa "7" significa en la declaración anterior? ¿Es lo mismo que

d = y / 7;

es que el mismo significado de "7"?

Casos de prueba son un problema ligeramente diferente. No necesitamos extensa manejo cuidadoso de cada instancia de un literal numérico,. En cambio, necesitamos documentación.

Podemos - hasta cierto punto - explicar dónde "7" viene de mediante la inclusión de una pequeña cantidad de un toque en el código

.
assertEquals( 7, someFunction(3,4), "Expected 7, see paragraph 7 of use case 7" );

Una "constante" deben establecerse - denominado -. Exactamente una vez

Un "número" en una unidad de prueba no es lo mismo que una constante, y requiere un poco de cuidado en la explicación de donde vino.

Un hex literal es no es diferente de un literal como decimal 1. Cualquier significado especial de un valor se debe al contexto de un programa en particular.

No hay ninguna razón por qué no debe asignar a una variable 0xdeadbeef.

Pero ¡ay de los programador que intenta asignar 3735928559 decimal o 33653337357 octal o lo peor de todo:. 11011110101011011011111011101111 binario

big endian o little endian?

Uno de los peligros es cuando las constantes se asignan a una matriz o estructura con diferentes miembros de tamaño; endian -ness del compilador o de la máquina (incluyendo JVM vs CLR) afectará el orden de los bytes.

Este problema es el caso de valores no constantes, también, por supuesto.

Esto es una, sin duda artificial, ejemplo. ¿Cuál es el valor de buffer [0] después de la última línea?

const int TEST[] = { 0x01BADA55,  0xDEADBEEF };
char buffer[BUFSZ];

memcpy( buffer, (void*)TEST, sizeof(TEST));

No veo ningún problema con el uso como un valor. Es sólo un número después de todo.

No hay peligro en el uso de un valor hexadecimal codificado para un puntero (como su primer ejemplo) en el contexto adecuado. En particular, cuando se hace el desarrollo de hardware de nivel muy bajo, esta es la forma de acceder a los registros en configuración de memoria. (Aunque lo mejor es darles nombres con un # define, por ejemplo.) Sin embargo, a nivel de aplicación que no debe necesitar hacer una misión así.

Yo uso CAFEBABE No he visto que se usa por cualquier depuradores antes.

int *i = 0xDEADBEEF;
// god knows if that location is available

int i = 0xDEADBEEF;
// what can go wrong?

El peligro que veo es la misma en ambos casos: se ha creado un valor de indicador que no tiene contexto inmediato. No hay nada acerca i en cualquiera de los casos que me permita saber 100, 1000 o 10000 líneas que hay un valor de indicador potencialmente crítico asociado a él. Lo que se ha plantado minas terrestres es un error que, si no recuerdo para comprobar que en todos los usos posibles, que podrían tener que enfrentarse con un problema de la depuración terrible. Cada uso de i ahora tendrá que tener este aspecto:

if (i != 0xDEADBEEF) { // Curse the original designer to oblivion
    // Actual useful work goes here
}

Repetir lo anterior para todos los 7000 casos en los que es necesario utilizar i en el código.

Ahora, ¿por qué es lo anterior peor que esto?

if (isIProperlyInitialized()) { // Which could just be a boolean
    // Actual useful work goes here
}

Como mínimo, puedo detectar varios problemas críticos:

  1. Ortografía : Soy un terrible mecanógrafa. La facilidad con que va a detectar 0xDAEDBEEF en una revisión de código? O 0xDEADBEFF? Por otro lado, sé que mi compilación va a vomitar inmediatamente en isIProperlyInitialised () (obligatorio insertar el s vs z debate aquí).
  2. La exposición de significado . En lugar de tratar de ocultar sus banderas en el código, que ha creado intencionalmente un método que el resto del código se puede ver.
  3. Oportunidades para el acoplamiento . Es completamente posible que un puntero o referencia está conectado a una memoria caché vagamente definido. Una verificación de inicialización podría estar sobrecargado comprobar primero si el valor está en la memoria caché, a continuación, tratar de llevarlo de nuevo en caché y, si todo eso falla, vuelva falsa.

En resumen, es igual de fácil que escribir el código que realmente necesita, ya que es para crear un valor mágico misterioso. El código-mantenedor del futuro (que muy probablemente será usted) se lo agradecerá.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top