Por que o pré-processador C no GCC interpreta a palavra linux
(letras minúsculas) como constante 1
?
test.c:
#include <stdio.h>
int main(void)
{
int linux = 5;
return 0;
}
Resultado de $ gcc -E test.c
(parar após o estágio de pré-processamento):
....
int main(void)
{
int 1 = 5;
return 0;
}
O que, é claro, gera um erro.
(Entre: não há #define linux
no stdio.h
arquivo.)
c
linux
gcc
c-preprocessor
ahmedaly50
fonte
fonte
#undef linux
, ou talvez usando uma variável diferente? Eu acho que a constantelinux
é usada para testar sistemas operacionais, por exemplo, se você está projetando um aplicativo de plataforma cruzada e precisa saber exatamente qual API usar (Windows, Mac, Linux, BSD, etc). Não está no stdio.h, mas ainda está definido se o kernel é linux. O mesmo código não deve produzir um erro no Windows, mas usando algo como Windows ou Windows como a variável provavelmente vai, e vice-versaRespostas:
Nos velhos tempos (pré-ANSI), predefinir símbolos como
unix
evax
era uma maneira de permitir que o código detectasse em tempo de compilação em que sistema estava sendo compilado. Não havia um padrão de idioma oficial na época (além do material de referência no final da primeira edição da K&R), e o código C de qualquer complexidade era tipicamente um labirinto complexo de#ifdef
s para permitir diferenças entre os sistemas. Essas definições de macro geralmente eram definidas pelo próprio compilador, não definidas em um arquivo de cabeçalho da biblioteca. Como não havia regras reais sobre quais identificadores poderiam ser usados pela implementação e quais eram reservados para programadores, os criadores de compiladores sentiram-se à vontade para usar nomes simples comounix
e assumiram que os programadores simplesmente evitariam usar esses nomes para seus próprios fins.O padrão ANSI C de 1989 introduziu regras que restringem quais símbolos uma implementação pode legalmente predefinir. Uma macro predefinida pelo compilador só pode ter um nome que comece com dois sublinhados ou com um sublinhado seguido de uma letra maiúscula, deixando os programadores livres para usar identificadores que não correspondem ao padrão e não são usados na biblioteca padrão.
Como resultado, qualquer compilador que predefinir
unix
oulinux
não estiver em conformidade, pois ele falhará ao compilar um código perfeitamente legal que use algo parecidoint linux = 5;
.Por acaso, o gcc não está em conformidade por padrão - mas pode ser feito para estar em conformidade (razoavelmente bem) com as opções corretas da linha de comando:
Veja o manual do gcc para mais detalhes.
O gcc eliminará essas definições em versões futuras, portanto você não deve escrever código que dependa delas. Se o seu programa precisa saber se está sendo compilado para um destino Linux ou não, pode verificar se
__linux__
está definido (supondo que você esteja usando o gcc ou um compilador compatível com ele). Veja o manual do pré-processador GNU C para mais informações.Um aspecto amplamente irrelevante: o vencedor do "Best One Liner" do Concurso Internacional de Código C Ofuscado de 1987 , de David Korn (sim, o autor do Korn Shell) aproveitou a
unix
macro predefinida :Ele é impresso
"unix"
, mas por motivos que não têm absolutamente nada a ver com a ortografia do nome da macro.fonte
unix
evax
" - Hein? Entendi que, nos velhos tempos, todo o mundo era umvax
!unix
definição). Expliquei por que, em um comentário sobre essa essência, se você ou qualquer outra pessoa está curiosa.Parece ser uma "extensão GNU" (não documentada): [ correção : finalmente encontrei uma menção nos documentos. Ver abaixo.]
O comando a seguir usa a
-dM
opção para imprimir todas as definições do pré-processador; Como o "arquivo" de entrada está vazio, mostra exatamente as macros predefinidas. Foi executado com o gcc-4.7.3 em uma instalação padrão do ubuntu. Você pode ver que o pré-processador reconhece o padrão. No total, existem 243 macros com-std=gnu99
e 240 com-std=c99
; Eu filtrei a saída por relevância.As versões "gnu standard" também
#define unix
. (Usandoc11
egnu11
produz os mesmos resultados.)Suponho que eles tenham suas razões, mas me parece que a instalação padrão do gcc (que compila o código C com
-std=gnu89
exceção do contrário) não é conforme e, como nesta pergunta, é surpreendente. Poluir o espaço de nomes global com macros cujos nomes não começam com um sublinhado não é permitido em uma implementação em conformidade. (6.8.10p2: "Quaisquer outros nomes de macro predefinidos devem começar com um sublinhado inicial seguido de uma letra maiúscula ou um segundo sublinhado", mas, como mencionado no Apêndice J.5 (problemas de portabilidade), esses nomes geralmente são predefinidos.)Quando escrevi essa resposta originalmente, não consegui encontrar nenhuma documentação no gcc sobre esse problema, mas finalmente a descobri, não no comportamento definido pela implementação C nem nas extensões C, mas na
cpp
seção manual 3.7.3 , em que observa que:fonte
-std=gnu89
é o padrão, e até onde eu sei, é o padrão no solaris, linux e mac os x ( developer.apple.com/library/mac/documentation/Darwin/Reference/… para o último), e é aquele que polui o espaço para nome.c89
tenta estar em conformidade com o padrão, portanto, se fosse o padrão, não teria uma reclamação.Porque
linux
é uma macro interna definida quando o compilador está sendo executado ou compilando (se for um compilador cruzado), Linux.Existem muitas macros predefinidas. Com o GCC, você pode usar:
para obter uma lista de macros. (Não consegui convencer o GCC a aceitar
/dev/null
diretamente, mas o arquivo vazio parece funcionar bem.) Com o GCC 4.8.1 em execução no Mac OS X 10.8.5, obtive a saída:São 236 macros de um arquivo vazio. Quando adicionei
#include <stdio.h>
ao arquivo, o número de macros definidas subiu para 505. Isso inclui todos os tipos de macros de identificação de plataforma.fonte
cpp -dM < /dev/null
linux
) não está definido na minha máquina Mac OS X - não está executando o Linux (bem, há uma VM executando o Linux, mas ...). Pode ser definido pelos cabeçalhos incluídos por<stdio.h>
; executar um arquivo vazio pode não ser o mesmo./dev/null
como um arquivo de origem,-x
pois ele não possui uma extensão; portanto, o gcc não sabe se é C ou C ++. Você pode usargcc -E -dM -x c /dev/null
ougcc -E -dm -x c++ /dev/null
obter a lista sem precisar criar um arquivo vazio.cpp
(o pré-processador) nãogcc
. Note também que eu não dar-lhe/dev/null
como um arquivo de entrada, mas eu estou usando o redirecionamento para fazer/dev/null
emstdin
. Também @KerrekSB: na minha máquina debianlinux
está na lista.> emptyfile.c
ou: > emptyfile.c
oudd if=/etc/passwd of=emptyfile.c count=0
ou ...De
info gcc
(ênfase minha):(Ele usa vax no exemplo, em vez de linux, porque quando foi escrito, talvez fosse mais popular ;-).
A ideia básica é que o GCC apenas tente cumprir totalmente os padrões ISO quando for invocado com a
-ansi
opção.fonte
-ansi
oustd=cXX
, ondeXX
é89
,90
,99
, ou11
, e quer-pedantic
ou-pedantic-errors
. Até isso é uma simplificação excessiva; veja o manual para detalhes.Use este comando
para conseguir esta
fonte