4 Comentários

Quiz – Definição múltipla de variáveis globais

definição

Quem ainda não sofreu com erro de compilação com relação à definição múltipla de uma mesma variável ou função? Pois bem, com o objetivo de ajudar a elucidar as dúvidas mais básicas de programação em C, preparamos um exemplo bem simples de um cenário de definição múltipla de variáveis globais num projeto. Veja um exemplo:

main.c

 bar.c

 bar.h

 Compilação

O que acontece na compilação? Ela é bem sucedida? Ou, ainda, ocorre um erro na link-edição do binário executável? Pode-se, também, gerar um arquivo executável com sucesso, no entanto a sua execução poderia apresentar um comportamento indesejado. Participem desse quiz e fiquem à vontade para comentar!

Resposta

Chegou a hora da resposta! Esse quiz contou com 52 votos. As alternativas oferecidas e os respectivos números de votos são:

  • Mensagens: foo = 2 foo de bar = 2 (12 votos - 23%)
  • Mensagens: foo = 0 foo de bar = 0 (3 votos - 6%)
  • Erro de compilação (10 votos - 19%)
  • Erro de link-edição (27 votos - 52%)

As regras do jogo são estabelecidas pelo padrão da linguagem C. É um trabalho de advogado! Consultando o documento ISO/IEC 9899:TC3, conhecido como C99, no item 6.9.2, temos o seguinte texto:

6.9.2 External object definitions

Semantics

1 If the declaration of an identifier for an object has file scope and an initializer, the declaration is an external definition for the identifier.

2 A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition. If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.

No nosso exemplo, a declaração de foo em bar.c é uma definição, pois requisita ao compilador a alocação de espaço na memória do sistema para a variável em questão. Trata-se de um identicador com linkagem externa e escopo de arquivo. A seguir podemos ver como o compilador tratou essa variável:

O compilador alocou a variável foo na seção de dados inicializados. Perfeito! Essa inicialização é realizada antes da chamada à função main(), na etapa de start-up.

Mas o que acontece com a declaração da variável foo em main.c? Ela é tratada, de acordo com o padrão da linguagem, como uma tentative definition com linkagem externa, pois não oferece um inicializador e não contém o especificador de armazenamento static. Esse tipo de identificador é tratado no GCC como um símbolo comum, como pode ser observado no arquivo binário, no formato ELF, main.o:

Esse tipo de símbolo representa dados não inicializados. Múltiplos símbolos comuns podem existir ao longo de outros arquivos-objeto, sendo que somente uma definição com um inicializador pode existir. Quando essa última é encontrada pelo linker, as outras declarações são tratadas como referências não definidas.

Veja que no binário executável ELF final, o símbolo foo é alocado na seção de dados inicializados.

Portanto, não existe erro nem de compilação, nem de link-edição. E a resposta é:

Acharam que era outra resposta? Deixem seus comentários justificando as suas escolhas!

Muito obrigado pessoal pela participação! Teremos outros quizzes pela frente. Quer saber quando teremos mais um? Estejam ligados nas nossas redes sociais:

Facebook: https://www.facebook.com/osembarcados

LinkedIn: http://www.linkedin.com/groups/Os-Embarcados-6511589

Twitter: @embarcados

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Software » Quiz - Definição múltipla de variáveis globais
Comentários:
Notificações
Notificar
guest
4 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Adriano Oliveira Pires
AdrianoOP
09/02/2014 14:07

Se eu tivesse:

no arquivo bar.c:

int foo = 2;

void bar_print_foo(void)
{
foo = 0;
printf("foo de bar = %dn", foo);
}

e no main.c:

int foo;

int main(void)
{
foo = 1;
printf("foo = %dn", foo);
bar_print_foo();

return 0;
}

qual seria o resultado?

Henrique Rossi
Reply to  AdrianoOP
09/02/2014 14:20

Adriano, O resultado seria: foo = 1 foo de bar = 0 No exemplo mencionado não são alteradas as declarações/definições da variável foo, e sim somente são adicionadas algumas atribuições à ela ao longo do código. Portanto: A variável foo, antes de ser alterada pela função main(), é inicializada com o valor 2. Em main() seu valor é modificado explicitamente para 1, o que faz a chamada à função printf() exibir a saída: foo = 1 Quando a função bar_print_foo() é chamada, o valor da variável foo é alterado novamente, agora para 0. Assim, a chamada à função printf exibi… Leia mais »

Adriano Oliveira Pires
AdrianoOP
09/02/2014 13:57

Hahaha! Muito bom!

Será que existe algum tipo de diretiva de compilação que possa alterar este resultado ou causar o erro "esperado" (erro de link de acordo com 52% das respostas)?

Henrique Rossi
Reply to  AdrianoOP
09/02/2014 14:07

Olá Adriano!

Muito boa a pergunta! Não existe uma diretiva de compilação para gerar esse comportamento. Mas existe uma forma de causar um erro de link-edição: criando duas definições da variável foo, ambas com linkagem externa e com inicializadores. Exemplo:

Em main.c, altere a declaração da variável foo, por exemplo, para:

int foo = 3;

O valor de inicialização não importa, contanto que ele seja explícito.

Compile! O erro de link-edição ocorre, mencionando que uma declaração múltipla da variável foo foi encontrada.

Abraços,
Henrique

Talvez você goste:

Séries

Menu

WEBINAR
 

Soluções inteligentes para acionamento de MOSFETs/IGBTs com família STDRIVE

Data: 08/10 às 15:00h - Apoio: STMicroelectronics
 
INSCREVA-SE AGORA »



 
close-link