Esto parece ser una "extensión GNU" (no documentada):[corrección :finalmente encontré una mención en los documentos. Ver más abajo.]
El siguiente comando usa el -dM
opción para imprimir todas las definiciones del preprocesador; dado que el "archivo" de entrada está vacío, muestra exactamente las macros predefinidas. Se ejecutó con gcc-4.7.3 en una instalación estándar de ubuntu. Puede ver que el preprocesador tiene en cuenta los estándares. En total, hay 243 macros con -std=gnu99
y 240 con -std=c99
; Filtré la salida por relevancia.
$ cpp --std=c89 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
$ cpp --std=gnu89 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
#define linux 1
$ cpp --std=c99 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
$ cpp --std=gnu99 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
#define linux 1
Las versiones "estándar gnu" también #define unix
. (Usando c11
y gnu11
produce los mismos resultados.)
Supongo que tenían sus razones, pero me parece que hacer la instalación por defecto de gcc (que compila código C con -std=gnu89
a menos que se especifique lo contrario) no conforme y, como en esta pregunta, sorprendente. No se permite contaminar el espacio de nombres global con macros cuyos nombres no comienzan con un guión bajo en una implementación conforme. (6.8.10p2:"Cualquier otro nombre de macro predefinido debe comenzar con un guión bajo seguido de una letra mayúscula o un segundo guión bajo", pero, como se menciona en el Apéndice J.5 (problemas de portabilidad), dichos nombres a menudo están predefinidos).
Cuando originalmente escribí esta respuesta, no pude encontrar ninguna documentación en gcc sobre este problema, pero finalmente lo descubrí, no en el comportamiento definido por la implementación de C ni en las extensiones de C, sino en el cpp
sección 3.7.3 del manual, donde se señala que:
Estamos eliminando gradualmente todas las macros predefinidas que están fuera del espacio de nombres reservado. Nunca debes usarlos en programas nuevos...
En los viejos tiempos (pre-ANSI), símbolos predefinidos como unix
y vax
era una forma de permitir que el código detectara en tiempo de compilación para qué sistema se estaba compilando. No había un estándar de idioma oficial en ese entonces (más allá del material de referencia en la parte posterior de la primera edición de K&R), y el código C de cualquier complejidad era típicamente un complejo laberinto de #ifdef
s para permitir diferencias entre sistemas. Estas definiciones de macro generalmente fueron establecidas por el propio compilador, no definidas en un archivo de encabezado de biblioteca. Dado que no había reglas reales sobre qué identificadores podía usar la implementación y cuáles estaban reservados para los programadores, los escritores de compiladores se sintieron libres de usar nombres simples como unix
y asumió que los programadores simplemente evitarían usar esos nombres para sus propios fines.
El estándar ANSI C de 1989 introdujo reglas que restringían qué símbolos podía predefinir legalmente una implementación. Una macro predefinida por el compilador solo podía tener un nombre que comenzara con dos guiones bajos, o con un guión bajo seguido de una letra mayúscula, lo que dejaba a los programadores libres para usar identificadores que no coincidieran con ese patrón y que no se usaran en la biblioteca estándar.
Como resultado, cualquier compilador que predefina unix
o linux
no es conforme, ya que no podrá compilar un código perfectamente legal que use algo como int linux = 5;
.
Da la casualidad de que gcc no se ajusta de forma predeterminada, pero se puede hacer que se ajuste (razonablemente bien) con las opciones correctas de la línea de comandos:
gcc -std=c90 -pedantic ... # or -std=c89 or -ansi
gcc -std=c99 -pedantic
gcc -std=c11 -pedantic
Consulte el manual de gcc para obtener más detalles.
gcc eliminará gradualmente estas definiciones en futuras versiones, por lo que no debe escribir código que dependa de ellas. Si su programa necesita saber si está siendo compilado para un destino Linux o no, puede verificar si __linux__
está definido (suponiendo que esté usando gcc o un compilador que sea compatible con él). Consulte el manual del preprocesador GNU C para obtener más información.
Un aparte en gran parte irrelevante:el ganador de "Best One Liner" del Concurso internacional de código C ofuscado de 1987, de David Korn (sí, el autor de Korn Shell) aprovechó el unix
predefinido macro:
main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}
Imprime "unix"
, pero por razones que no tienen absolutamente nada que ver con la ortografía del nombre de la macro.