2010-07-20 5 views
14

¿Por qué hay una diferencia en la salida producida cuando el código se compila utilizando los dos compiladores gcc y turbo c.Diferencia de salida en gcc y turbo C

#include <stdio.h> 

int main() 
{  
    char *p = "I am a string"; 
    char *q = "I am a string"; 

    if(p==q) 
    { 
     printf("Optimized"); 
    } 
    else{ 
     printf("Change your compiler"); 
    } 
    return 0; 
} 

me sale "Optimized" en gcc y "Change your compiler" en turbo c. ¿Por qué?

+27

Tome la sugerencia; Para utilizar gcc ;-) – Amarghosh

+1

visto que las respuestas de la pregunta ya están incluidos en las cadenas 'printf' (Por cierto que hay '\ n' faltaban allí) supongo que recibió este ejemplo de código de alguna parte? ¿Es esta tarea? –

+1

FWIW, si está hablando del compilador antiguo de Borland, creo que tiene una opción de línea de comando ('-d') para unir constantes de cadena. – msandiford

Respuesta

33

Sus preguntas han sido etiquetadas C y C++. Entonces respondería por los dos idiomas.

[C]

A partir de ISO C99 (Section 6.4.5/6)

It is unspecified whether these arrays are distinct provided their elements have the appropriate values.

Eso significa que es unspecified si p y q están apuntando a la misma cadena literal o no. En caso de gcc que ambos están apuntando a "I am a string" (gcc optimiza su código), mientras que en turbo c no lo son.

no especi Comportamiento fi ed: El uso de un valor no especi fi ed, u otro comportamiento donde esta Norma Internacional proporciona dos o más posibilidades y no impone requisitos adicionales en que se elige en cualquier ejemplo


[C++]

De ISO C++ - 98 (Section 2.13.4/2)

Whether all string literals are distinct(that is, are stored in non overlapping objects) is implementation defined.

en C++ invoca el código de conducta de implantación definidos.

Implementación de fi nida Comportamiento: Comportamiento especi fi cado que cada aplicación documents cómo se hace la elección


Véase también this cuestión.

+7

+1 por haber informado el significado definido como estándar subjetivo del comportamiento "no especificado"/"implementación definida". – ShinTakezou

+6

+1 para una respuesta muy completa! –

+0

Gracias @Shin y @Amardeep :) –

15

Dado que el literal de su cadena es una expresión constante, es decir, no debe modificarla mediante un puntero, no tiene sentido almacenarla en el espacio de la memoria dos veces. Siendo un compilador más nuevo, gcc combina los literales de forma predeterminada mientras que el Turbo C no. Es una señal del apoyo de gcc para el estándar de lenguaje más nuevo que tiene la noción de datos const.

+2

Puede anular este comportamiento en gcc pasando la opción '-fno-merge-constants', aunque en general no hay una buena razón para hacerlo. – Hasturkun

+0

@Hasturkun: Buen consejo :) @Amardeep: ¡Muy buena respuesta! –

+1

@Amardeep, su respuesta no es del todo correcta. Un literal de cadena no es una expresión constante, de lo contrario no habría sido posible asignarlo a un 'char *'. Es cierto, que uno * no debería * cambiarlo luego accediendo a través del puntero, pero está permitido. El comportamiento no está definido ... En cualquier caso, no entiendo a las personas que dan asignaciones como esa que muestran esos malos hábitos. Esto siempre debe ser un 'char const *' al cual se le asigna dicha dirección de un literal de cadena. –

1

El compilador puede conservar dos copias de literales idénticos si lo considera apropiado. Descubrir si ese es el caso es presumiblemente el objetivo de este programa.

En los viejos tiempos, los ensambladores tenían todos los literales en un conjunto literal, y parchear el conjunto literal era una técnica reconocida (si no aprobada) de modificación de "constantes" a lo largo del programa.

Si por alguna casualidad el compilador permite en este caso *p = 'H'; diferencias importantes en el comportamiento y luego darían lugar.

+0

Debería decirse que, en muchas versiones anteriores (anteriores a ANSI) de C, se permitía la modificación de cadenas literales. – JeremyP

+0

@JeremyP: defina "Permitido". Estoy bastante seguro de que siempre fue un comportamiento indefinido (un sistema embebido podría haber puesto esa cadena en la ROM) (aunque técnicamente, pre-ANSI, everytihng fue oficialmente "un comportamiento indefinido") –

+0

Compiladores para sistemas embebidos suelen dar a sus usuarios de grano muy fino controlar sobre dónde va cada cosa Es poco probable que los literales de cadena entren en la ROM y no puedas hacer nada al respecto. –

3

Turbo C fue optimizado para una compilación rápida, por lo que no tiene ninguna característica que lo desacelere. Reconocer cadenas duplicadas sería una desaceleración, aunque solo sea menor.

+4

Creo que esta explicación es incorrecta. Los valores predeterminados de Turbo C están simplemente ahí para permitir que el código roto modifique las constantes de cadena para que funcionen de manera predeterminada. –

5

Desde la página de manual de gcc:

-fmerge constantes de

Intentar mezclar constantes idénticas (constantes de cadena y constantes de coma flotante) a través de unidades de compilación.

Esta opción es el valor predeterminado para la compilación optimizada si el apoyo ensamblador y enlazador . Use -fno-merge-constants para inhibir este comportamiento.

Habilitado a niveles -O, -O2, -O3, -OS.

Por lo tanto la salida.

10

Por favor, olvidemos las respuestas en la misma línea que

"Es porque Turbo C es tan totalmente VIEJO y no podían hacerlo, entonces, porque tenía que ser rápido, pero el CCG es totalmente ¡NUEVO y RAD y es por eso que hace eso! ".

Ambos compiladores admiten la fusión de constantes de cadena como una opción. La opción GCC (-fmerge-constants) se activa en los niveles de optimización, mientras que la opción Turbo C (-d) está desactivada de forma predeterminada. Si está utilizando el IDE de TCC, vaya a Options|Compiler...|Code Generation.. y marque "Duplicate strings merged".

+1

Encontré su respuesta difícil de leer e inicialmente la malentendí por completo, porque la cita no era muy claramente reconocible como tal. Espero que estés bien con mis cambios de formato. Aparte de eso, información buena y útil para cualquier persona que todavía esté tratando con TC, entonces: +1. –

+0

Oh, eso es mucho mejor. ¡Gracias! –

0

nota histórica: Dado que las direcciones eran más pequeños que de punto flotante constantes numéricas, FORTRAN utiliza para manejar las constantes de punto flotante al igual que C se encarga de cuerdas. Como la memoria era preciosa, a las constantes idénticas se les asignaría el mismo espacio. Además, el paso de parámetros siempre se realizó por referencia. Esto significaba que si uno pasaba una constante numérica a un procedimiento que modificaba su argumento, otras ocurrencias de esa "constante" cambiarían de valor.

De ahí el viejo dicho: "Las variables no; no son constantes."

Por cierto, ¿alguien ha notado el error en la impresión Turbo C 2.0 que fallaría al usar un formato como "% 1.1f" para imprimir números como 99.99 (salidas 00.0)? Solucionado en 2.01, me recuerda el error de la calculadora de Windows 3.1.