Estoy leyendo a través de algún emulador de código y he contrarrestado algo realmente extraño:

switch (reg){
    case 'eax':
    /* and so on*/
}

¿Cómo es esto posible? Yo pensaba que sólo se podía switch integral de tipos. Hay algunos macro engaño pasando?

  • no es la cadena 'eax' y enumera constante valor entero
  • Las comillas simples, no doble. Una constante de caracteres es promovido a int, por lo que es legal. Sin embargo, el valor de un multi-carácter constante de la implementación definidos, por lo que el código podría no funcionar como se espera en otro compilador. Por ejemplo, eax podría ser 0x65, 0x656178, 0x65617800, 0x786165, 0x6165, o algo más.
  • dado el nombre de la variable «reg», y el hecho de que eax es un x86 registrar, me imagino que la aplicación definida por el comportamiento y la intención era ACEPTAR, porque es el mismo en todas partes se usa en el código. Tan largo como 'eax' != 'ebx', de curso, por lo que sólo se presenta uno o dos de sus ejemplos. Aunque podría haber algún código en algún lugar que, en efecto, se supone *(int*)("eax") == 'eax', y por tanto no la mayoría de sus ejemplos.
  • No estoy en desacuerdo con lo que dices, pero existe el peligro real de que alguien podría intentar compilar el código de un compilador diferente, incluso para la misma arquitectura, y obtener un comportamiento diferente. Por ejemplo, 'eax' podría comparar de igual a 'ebx' o a 'ax', y la instrucción switch no funciona como se pretende.
  • Todo ese misterio habría sido rápidamente disipados si los había visto/nos muestra el tipo de datos de reg.
  • Por cierto, me gustaría que tienden a considerar este código apestoso. ¿Por qué no el diseñador original basta con definir una constante enumerada reg_eax con un buen valor, como el cero? switch declaraciones que abarca conjuntos de no consecutivos, los grandes valores no se compila en buen salto tablas.

InformationsquelleAutor Ian Colton | 2017-08-07

4 Comentarios

  1. 145

    (Sólo se puede responder a la «macro engaño» parte – a menos que pegar más de código. Pero no hay mucho aquí para macros de trabajo en – formalmente no está permitido redefinir palabras clave; el comportamiento en hacer que no está definida.)

    Con el fin de lograr la legibilidad, el ingenioso programador es la explotación de definido por la implementación de comportamiento. 'eax' es no una cadena, sino un de carácter multi-constante. Nota muy cuidadosamente las comillas simples personajes alrededor de eax. Lo más probable es que te da un int en su caso, que es único para esa combinación de caracteres. (Bastante a menudo, cada carácter ocupa 8 bits en 32 bits int). Y todo el mundo sabe que se puede switch en un int!

    Finalmente, un estándar de referencia:

    El estándar C99 dice:

    6.4.4.4p10: «El valor de un entero constante de caracteres que contiene más de un carácter (por ejemplo, ‘ab’), o que contienen un carácter o
    la secuencia de escape que no se asigna a un solo byte de ejecución
    carácter, es de aplicación definido.»

    • Sólo en caso de que alguien ve eso y entra en pánico, «la aplicación definida» es necesario trabajar y ser documentado por el compilador en algunos apropiado de la moda (la norma no requiere que el comportamiento sea intuitiva o que la documentación de cualquier ser bueno, pero…). Este es «seguro» para el uso de un codificador de que entiende completamente lo que está escrito, como opuesto a «no definido».
    • Sólo una nota: la intención original era de caracteres multibyte como Unicode. Uno UTF8 «carácter» en la pantalla puede ser de hasta cuatro bytes.
    • Me parece una implantación conforme no podía hacer algo raro como definir todos los multi-constantes de caracteres a ser iguales, por lo que sólo ciegamente el uso de ellos no parece una buena idea. Debería consultar a su aplicación a la documentación antes de hacer suposiciones acerca de ellos
    • Mientras pudo, que sería muy perversa. Si no hace lo que la respuesta sugiere que es más probable, la siguiente posibilidad es, probablemente, que sólo se utiliza el primer carácter y omite el resto.
    • la gente que escribe los compiladores no son (en general) una locura, así que trate de mapa de aplicación definido construcciones en un útil y de la lógica camino, y emitir advertencias cuando ellos no pueden. Porque… de ingeniería. -ex compilador chico.
    • Tener oficialmente «undefined» comportamiento en el que el compilador se permite a los demonios de la mosca de la nariz, hasta el punto de que tienes que constantemente protección contra accidentalmente invocarlo, es bastante perverso para empezar…
    • Su «segunda posibilidad» refuerza mi punto principal: antes de hacer suposiciones sobre lo que multibyte constantes decir, usted debe consultar a su aplicación a la documentación de
    • No estoy seguro, pero creo que la característica de tiempo anterior a Unicode y otros MBCS normas. «Números mágicos» que se ven como texto en los volcados de memoria y RIFF al estilo de formato de archivo-chunk IDs fueron las primeras aplicaciones soy consciente de.
    • Este no es un comportamiento indefinido, es de aplicación definido. Así que a menos que el compilador de la documentación menciona que los demonios, su nariz es seguro.
    • Un comportamiento indefinido usualmente se esconde en los lugares que tienen para protegerse de todos modos, así que no es realmente una descripción imparcial.
    • Me temo que la intención original es anterior a Unicode, UTF-8 y de cualquier codificación de caracteres multibyte por casi 20 años. multi-constante de caracteres eran sólo una forma útil de expresar los números enteros que representan grupos de 2, 3 o 4 bytes (dependiendo del byte int y tamaños). Las incoherencias entre las implementaciones de arquitecturas y llevado a la comisión a declarar esto como definido por la implementación, que significa que no hay manera portátil para calcular el valor de 'ab' de 'a' y 'b'.
    • Estoy bastante seguro de que usted está equivocado acerca de eso. Siempre se trataba de codificación de juegos de caracteres de otros idiomas aparte del inglés ASCII. La capacidad para hacer un entero de 4 bytes es feliz coincidencia..
    • aquí está una interesante página en la multi-caracteres: zipcon.net/~swhite/docs/equipos/idiomas/… y mirando hacia atrás más lejos en el espejo retrovisor, aquí está el original C manual de los buenos viejos tiempos: bell-labs.com/usr/dmr/www/cman.pdf .
    • las constantes de caracteres […] las constantes de Caracteres se comportan exactamente igual que los números enteros (no, en particular, como los objetos de tipo carácter). De conformidad con el direccionamiento de la estructura de la PDP-11, una constante de caracteres de longitud 1 tiene el código para el carácter en el byte de orden inferior, y 0 en el byte de orden alto; una constante de caracteres de longitud 2 tiene el código del primer carácter en el byte bajo y que para el segundo personaje en el byte de orden alto. Las constantes de caracteres con más de un carácter son intrínsecamente dependientes de máquina y debe ser evitado.
    • La capacidad de interpretar una secuencia de cuatro caracteres a un sin signo de 32 bits valor fue apoyado por Macintosh compiladores de C, probablemente volviendo a sus 1986 (ya que previamente había sido apoyada por la Macintosh de los compiladores de Pascal). Tal vez algunas máquinas en algún lugar de utilizar los caracteres multi-byte, pero sin duda no eran comunes.
    • Me di cuenta de que. Yo estaba diciendo que el lenguaje es ya perversos, así que uno más perverso comportamiento no cambia mucho.
    • Multi-carácter de las constantes no tienen nada que ver con Unicode. Simplemente reflejar la idea de que muchos de los caracteres puede ser empaquetada en una palabra, y esto es muy útil para la creación de las constantes que escriben algo.
    • Apple ha añadido que la razón más probable de su plataforma estaba llena de «falta» códigos para la identificación de tipos y formatos de datos. Por ejemplo, los tipos de archivos. Códigos Fourcc fueron escogidos de los que escribe de algo cuando se interpreta como bytes ASCII.
    • Desde juegos de caracteres multibyte literales están exactamente en el mismo lugar en el estándar como distintos personajes, ambos son para no-ASCII soporte de idioma. De lo contrario, '♂' sería divertido.
    • Yup. El Software podría copiar y comparar tales cosas en una sola operación en un «LongInt» [Pascal] o «largo» [C], sino como herramientas para manipular archivos, aplicaciones o tipos de recursos que se puede mostrar en formato legible. De archivos, aplicaciones o tipos de recursos con menos de cuatro personajes eran en blanco-collar (de modo que una «snd» recurso sería tener un tipo de 0x736e6420), y el primer carácter de cada tipo de uso público fue menor que 0 x 80, por lo que la falta de un entero de 32 bits tipo en Pascal no causa ninguna extrañeza con esos tipos.
    • Por supuesto, ya que los caracteres constantes no son portables, lo que se hace en la portátil de C es FOURCC('m', 'o', 'o', 'v') a través de una macro. Es menos engorroso para ser capaz de utilizar 'moov'.
    • «Desde juegos de caracteres multibyte literales están exactamente en el mismo lugar en el estándar como distintos personajes, ambos son para no-ASCII soporte de idioma.» lógicamente no siga. Ellos están en el mismo lugar, porque ellos son sintácticamente relacionados; son las constantes de caracteres.
    • En los días cuando la gente de la escritura de compiladores para una plataforma que podría esperarse de honor que las plataformas de modismos, de la potabilidad de tales construcciones no era un problema. Si se está utilizando los Recursos de Macintosh Manager, Administrador de Archivos, o el Desktop Manager funciones, eso significaba que uno estaba escribiendo código para el Macintosh y por lo tanto sería el uso de un compilador diseñado para esa plataforma.
    • Solo me pregunto, ¿el uso de una falsa cuenta para hacer esta pregunta?

  2. 44

    De acuerdo con el Estándar de C (6.8.4.2 La instrucción switch)

    3 La expresión de cada caso, la etiqueta deberá ser una constante entera
    expresión

    y (6.6 expresiones Constantes)

    6 Un entero expresión de la constante de será de tipo entero y se
    sólo tiene operandos que son constantes enteras, las constantes de enumeración,
    las constantes de caracteres, sizeof expresiones cuyos resultados son constantes enteras, y constantes flotantes que son los operandos inmediatos de
    yesos. Los operadores Cast en un entero expresión de la constante de sólo
    convertir aritmética de los tipos para los tipos enteros, excepto como parte de un
    el operando del operador sizeof.

    Ahora, ¿cuál es 'eax'?

    El Estándar de C (6.4.4.4 las constantes de Caracteres)

    2 Un entero constante de caracteres es una secuencia de uno o más
    multibyte caracteres encerrada entre comillas simples
    , como en ‘x’…

    Así 'eax' es un entero constante de caracteres, de acuerdo con el párrafo 10 de la misma sección

    1. …El valor de un entero constante de caracteres que contiene más de un
      carácter (por ejemplo, ‘ab’), o que contienen un carácter o escapar
      la secuencia en la que no se asigna a un solo byte de ejecución de carácter, es
      la aplicación definida.

    Así que de acuerdo a la primera mención de la cita puede ser un operando de una constante entera expresión que puede ser utilizado como un caso de la etiqueta.

    Prestar atención a que una constante de caracteres (entre comillas simples) tiene el tipo int y no es el mismo que el de un literal de cadena (una secuencia de caracteres entre comillas) que tiene un tipo de una matriz de caracteres.

  3. 12

    Como otros han dicho, este es un int constante y su valor real es de aplicación definido.

    Supongo que el resto del código se ve algo como

    if (SOMETHING)
        reg='eax';
    ...
    switch (reg){
        case 'eax':
        /* and so on*/
    }

    Usted puede estar seguro de que » eax «en la primera parte tiene el mismo valor como» eax » en la segunda parte, así que todo funciona, ¿verdad? … malo.

    En un comentario @Davislor muestran algunas de las posibles valores para la «eax’:

    0x65, 0x656178, 0x65617800, 0x786165, 0x6165, o algo más

    Aviso el primer valor potencial? Que es sólo 'e', ignorando a los otros dos personajes. El problema es que el programa probablemente utiliza 'eax', 'ebx',
    y así sucesivamente. Si todas estas constantes tienen el mismo valor como 'e' usted termina con

    switch (reg){
        case 'e':
           ...
        case 'e':
           ...
        ...
    }

    Esto no parezca demasiado buena, no?

    La mejor parte acerca de la implementación de la «definido» es que el programador puede consultar la documentación de su compilador, y ver si hace algo sensible con estas constantes. Si lo hace, casa gratis.

    La parte mala es que algunos otros buenos compañeros puede tomar el código y tratar de compilar usando algún otro compilador. Instantánea de error de compilación. El programa no es portable.

    Como @zwol señaló en los comentarios, la situación no es tan malo como yo pensaba, en el mal caso de que el código no compila. Esto le dará al menos un nombre exacto del archivo y número de línea para el problema. Sin embargo, no se tiene un programa de trabajo.

    • aparte de alguna forma de assert('eax' != 'ebx'); //if this fails you can't compile the code because... hay nada de lo que el autor original podría hacer para evitar otros errores de compilador, sin el reemplazo de la construcción enteramente>
    • El caso de dos etiquetas con el mismo valor son una violación de la restricción (6.8.4.2p3: «…no hay dos en el caso de expresiones constantes en la misma sentencia switch tendrán el mismo valor después de la conversión») así que, mientras todo el código trata de los valores de estas constantes como opaco, esto está garantizado, ya sea al trabajo o a un error de compilación.
    • La peor parte es que el pobre hombre compilar en otro compilador probablemente no verá ningún tiempo de compilación error (conmutación en ints está bien); en cambio, tiempo de ejecución los errores de los cultivos…
  4. 1

    El fragmento de código utiliza un histórico rareza llamada de carácter multi-carácter constante, también conocido como multi-chars.

    'eax' es un entero constante cuyo valor es definido por la implementación.

    Aquí es una interesante página en la multi-chars y cómo pueden ser utilizadas, pero no debe:

    http://www.zipcon.net/~swhite/docs/computers/languages/c_multi-char_const.html


    Mirando hacia atrás más lejos en el espejo retrovisor, aquí es cómo el original C manual por Dennis Ritchie de los buenos viejos días ( https://www.bell-labs.com/usr/dmr/www/cman.pdf ) especificado de caracteres constantes.

    2.3.2 las constantes de Caracteres

    Una constante de caracteres es de 1 o 2 caracteres encerrada entre comillas simples » ' «. Dentro de una constante de caracteres en una única oferta debe ser precedida por una barra inclinada «\«. Algunos no los caracteres gráficos, y «\» sí, puede ser escapado de acuerdo a la siguiente tabla:

        BS \b
        NL \n
        CR \r
        HT \t
        ddd \ddd
        \ \

    El escape «\ddd» se compone de la barra invertida seguida por la 1, 2, o 3 dígitos octales que se toman para especificar el valor del carácter deseado. Un caso especial de esta construcción es «\0» (no seguida de un dígito), que indica un carácter nulo.

    Las constantes de caracteres se comportan exactamente igual que los números enteros (no, en particular, como los objetos de tipo carácter). De conformidad con el direccionamiento de la estructura de la PDP-11, una constante de caracteres de longitud 1 tiene el código para el personaje de
    el byte de orden inferior, y 0 en el byte de orden alto; una constante de caracteres de longitud 2 tiene el código del primer carácter en el byte bajo y que para el segundo personaje en el byte de orden alto. Las constantes de caracteres con más de un carácter son intrínsecamente dependientes de máquina y debe ser evitado.

    La última frase es todo lo que usted necesita para recordar acerca de esta curiosa construcción: las constantes de Caracteres con más de un carácter son intrínsecamente dependientes de máquina y debe ser evitado.

Dejar respuesta

Please enter your comment!
Please enter your name here