c++ c global-variables language-lawyer variable-declaration

¿C tiene una regla de definición como C++?



global-variables language-lawyer (2)

Creo que lo que está buscando es el capítulo §6.2.7 del estándar C11 , Tipo compatible y tipo compuesto , ( énfasis mío )

Todas las declaraciones que se refieran al mismo objeto o función tendrán un tipo compatible ; de lo contrario, el comportamiento es indefinido.

y relacionado con el tipo compatible,

Dos tipos tienen tipo compatible si sus tipos son iguales.

En su caso, int y unsigned int no son tipos compatibles. De ahí el comportamiento indefinido .

Solo para agregar un poco de claridad, en su fuente 2 , unsigned int var_global; es una declaración y no coincide con la otra declaración (y definición), por lo tanto, esto es UB.

Dicho esto, una declaración como

printf("%d /n",var_global);

siempre considerará que el argumento a %d es de tipo int . En caso de que el tipo y el especificador de formato no coincidan, volverá a invocar un comportamiento indefinido .

EDITAR:

Después de la edición, la respuesta es, use -fno-common para obtener el error deseado. ( falta extern es lo que te molesta, creo ).

Cotización del manual de GCC en línea,

-fno-common

En código C, controla la colocación de variables globales no inicializadas. Los compiladores de Unix C tradicionalmente han permitido múltiples definiciones de tales variables en diferentes unidades de compilación al colocar las variables en un bloque común. Este es el comportamiento especificado por -fcommon, y es el predeterminado para GCC en la mayoría de los destinos. Por otro lado, este comportamiento no es requerido por ISO C, y en algunos objetivos puede conllevar una velocidad o una penalización de tamaño de código en referencias variables. La opción -fno-common especifica que el compilador debe colocar variables globales sin inicializar en la sección de datos del archivo de objeto, en lugar de generarlas como bloques comunes. Esto tiene el efecto de que si se declara la misma variable (sin extern ) en dos compilaciones diferentes, obtendrá un error de definición múltiple cuando los vincula. En este caso, debe compilar con -fcommon en su lugar. La compilación con -fno-common es útil en objetivos para los que proporciona un mejor rendimiento, o si desea verificar que el programa funcionará en otros sistemas que siempre tratan las declaraciones de variables no inicializadas de esta manera.

No conozco ninguna mención de las palabras "una regla de definición" en el estándar C, pero a lo largo de la línea, puede consultar el anexo §J.5.11, Múltiples definiciones externas ,

Puede haber más de una definición externa para el identificador de un objeto, con o sin el uso explícito de la palabra clave extern ; Si las definiciones no están de acuerdo, o se inicializa más de una, el comportamiento no está definido.

Recientemente, descubrí que hay algunos casos que violarán absolutamente la ODR de C ++ pero que se compilarán correctamente en el compilador de C.

Por ejemplo, este extraño escenario (conmigo):

Fuente 1

int var_global=-3;

Fuente 2

#include <stdio.h> #include <conio.h> unsigned int var_global; int main() { printf("%d /n",var_global); getch(); return 0; }

Tengo el resultado impreso es -3 (aunque en Source 2 var_global unsigned está unsigned ) y no hay ningún error acerca de la redefinición de var_global .

Sabía que C tiene reglas diferentes con C ++, pero no creo que sea así de diferente.

Tengo Google y leo muchos resultados, pero no hay un resultado oficial como este de C ++.

Así que la pregunta es:

¿C tiene una regla de definición como C ++?

y:

¿Cómo se llama oficialmente?

Lo necesito para comparar con la regla de C ++ para que pueda entender los dos idiomas más profundamente.

p / s: Utilicé Visual Studio 2010 para compilar el código anterior.


Lo que está viendo no tiene nada que ver con una regla de una definición. Tiene que ver con el hecho de que %d espera un valor firmado y, por lo tanto, es casi seguro que lo tratará como un valor firmado en su implementación.

Sin embargo, esto no es algo en lo que debas confiar. Según el estándar C 7.19.6.1 The fprintf function /9 (estoy haciendo referencia a C99 pero C11 es bastante similar en términos de los aspectos que se muestran aquí):

Si algún argumento no es el tipo correcto para la especificación de conversión correspondiente, el comportamiento no está definido.

Ya que estás usando un comportamiento indefinido, la implementación es libre de hacer lo que quiera. Además, la norma también establece específicamente que es un comportamiento indefinido si (del Anexo J):

dos declaraciones del mismo objeto o función especifican tipos que no son compatibles.

En su caso, esas dos declaraciones sí especifican el mismo objeto, ya que ambas tienen enlaces externos.

Ahora puede pensar que los enteros con signo y sin signo serían compatibles, pero usted estaría equivocado: 6.2.7 Compatible and composite type , y 6.2.5 Types deja claro que las variantes con signo y sin signo no son compatibles:

Dos tipos tienen tipo compatible si sus tipos son iguales .

Para cada uno de los tipos de enteros con signo, hay un tipo de entero sin signo correspondiente (pero diferente ) (designado con la palabra clave sin signo) que utiliza la misma cantidad de almacenamiento (incluida la información de signos) y tiene los mismos requisitos de alineación.