Definiciones provisionales en C99 y enlaces


Considere el programa C compuesto de dos archivos,

F1.c:

int x;

F2.c:

int x=2;

Mi lectura del párrafo 6.9.2 de el estándar C99 es que este programa debe ser rechazado. En mi interpretación de 6.9.2, variable x se define tentativamente en f1.c, pero esta definición tentativa se convierte en una definición real al final de la unidad de traducción, y (en mi opinión), por lo tanto, debe comportarse como si f1.c contuviera la definición int x=0;.

Con todos los compiladores (y, lo que es más importante, los enlazadores) pude probar, esto no es lo que sucede. Todas las plataformas de compilación que probé enlazan los dos archivos anteriores, y el valor de x es 2 en ambos archivos.

Dudo que esto suceda por accidente, o simplemente como una característica "fácil" de proporcionar además de lo que requiere el estándar. Si lo piensas, significa que hay un soporte especial en el enlazador para aquellas variables globales que no tienen un inicializador, en oposición a aquellas explícitamente inicializado a cero. Alguien me dijo que la función de enlazador puede ser necesaria para compilar Fortran de todos modos. Esa sería una explicación razonable.

¿Alguna idea sobre esto? ¿Otras interpretaciones del estándar? ¿Nombres de plataformas en las que los archivos f1.c y f2.c se niegan a vincularse?

Nota: esto es importante porque la pregunta ocurre en el contexto del análisis estático. Si los dos archivos pueden negarse a vincularse en alguna plataforma, el analizador debe quejarse, pero si cada plataforma de compilación lo acepta, entonces no hay razón para advertir al respecto.

Author: ire_and_curses, 2009-09-29

3 answers

Ver también Qué son las variables externas en C. Esto se menciona en la norma C en el Anexo informativo J como una extensión común:

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 es indefinido (6.9.2).

Advertencia

Como @ litb puntos aquí, y como se indica en mi respuesta a la pregunta de referencia cruzada, el uso de múltiples definiciones para una variable global conduce a un comportamiento indefinido, que es la forma en que el estándar dice "cualquier cosa podría suceder". Una de las cosas que pueden suceder es que el programa se comporta como usted espera; y J. 5.11 dice, aproximadamente, "usted podría tener suerte más a menudo de lo que se merece". Pero un programa que se basa en múltiples definiciones de una variable extern-con o sin la palabra clave 'extern' explícita-es no es un programa estrictamente conforme y no garantiza que funcione en todas partes. Equivalentemente: contiene un bug que puede o no mostrarse.

 27
Author: Jonathan Leffler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:30:04

Hay algo llamado una "extensión común" al estándar, donde se permite definir variables varias veces siempre que la variable se inicialice solo una vez. Véase http://c-faq.com/decl/decldef.html

La página enlazada dice que esto es pertinente para las plataformas Unix guess supongo que es lo mismo para c99 que para c89 though aunque tal vez ha sido adoptado por más compiladores para formar algún tipo de estándar defacto. Interesante....

 9
Author: olovb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-29 05:42:55

Esto es para aclarar mi respuesta a un comentario de olovb:

Salida de nm para un archivo objeto compilado desde "int x;". En esta plataforma, los símbolos se anteponen con un '_', es decir, la variable x aparece como _x.

00000000 T _main
         U _unknown
00000004 C _x
         U dyld_stub_binding_helper

Salida de nm para un archivo objeto compilado desde "int x=1;"

00000000 T _main
         U _unknown
000000a0 D _x
         U dyld_stub_binding_helper

Salida de nm para un archivo objeto compilado desde "int x = 0;"

00000000 T _main
         U _unknown
000000a0 D _x
         U dyld_stub_binding_helper

Salida de nm para un archivo objeto compilado desde "extern int x;"

00000000 T _main
         U _unknown
         U dyld_stub_binding_helper

EDITAR: salida de nm para un objeto archivo compilado desde "extern int x;" donde x se usa realmente en una de las funciones

00000000 T _main
         U _unknown
         U _x
         U dyld_stub_binding_helper
 7
Author: Pascal Cuoq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-29 07:31:52