Erro em função C [RESOLVIDO]

1. Erro em função C [RESOLVIDO]

lucas
ljparaujo

(usa Debian)

Enviado em 20/04/2018 - 22:32h

Boa noite caros. Estou com um problema com um codigo em uma função para uma biblioteca em C.
Eis o codigo:

arquivo.c
#include "hashing_aberto.h"

void mostra_menu()
{
printf("\t\tHASHING ABERTO\n");
printf("\n[1] Inserir");
printf("\n[2] Mostrar vetor");
printf("\n");

}


arquivo.h
#ifndef HASHING_ABERTO_H
#define HASHING_ABERTO_H

void mostra_menu();

#endif


principal.c
#include <stdio.h>
#include "hashing_aberto.h"

int main()
{

mostra_menu();


return 0;
}


Este codigo e para tratar hash num vetor, antes havia colocado somente o prototipo da função, mas apaguei e o erro é este:

hashing_aberto.c: In function ‘inserir’:
hashing_aberto.c:7:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
/usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/Scrt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status


Mas não consegui entender qual o erro. Desde ja agradeço


  


2. Re: Erro em função C [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 21/04/2018 - 17:38h

Há dois erros (ou problemas) distintos nas mensagens que você mostrou.

O primeiro erro (ou problema, aviso, dado que a compilação prosseguiu) é o fato de você ter declarado uma função que inserir(), que você não mostrou na sua listagem, que você diz que deve retornar um valor, mas que chega ao final sem explicitamente retornar valor algum.

O outro erro (esse é um erro mesmo!) ocorre na etapa de linking, quando o linker tentar encontrar a função main(), mas não a encontra.

A explicação possível do segundo erro tem a ver com o fato de que você está usando compilação separada, e a função main() reside num arquivo distinto das funções da sua biblioteca. Provavelmente o que aconteceu foi que você errou ao tentar compilar o arquivo da sua biblioteca, instruindo o compilador a prosseguir até a geração do executável, em vez de fazê-lo apenas gerar o arquivo com código objeto, para ser passado posteriormente para o linker, junto com o código objeto que contém a função main().


3. Re: Erro em função C [RESOLVIDO]

lucas
ljparaujo

(usa Debian)

Enviado em 21/04/2018 - 18:19h

A função inserir que criei não tinha conteudo, somente o escopo da função, pois iria defini-la mais tarde. Como vi que teve o erro eu a apaguei, mas mesmo assim o erro persistiu, e não entendi o porque. De qualquer forma existe uma maneira de resolver isso ou eu devo criar codigos fontes novos ?


4. Re: Erro em função C [RESOLVIDO]

lucas
ljparaujo

(usa Debian)

Enviado em 21/04/2018 - 18:22h

E quanto à compilação eu compilei todos os aquivos com o comando: gcc -Wall *c -o principal
Creio que assim que é feita a compilação de todos ao mesmo tento ?


5. Re: Erro em função C [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 21/04/2018 - 23:30h

ljparaujo escreveu:

E quanto à compilação eu compilei todos os aquivos com o comando: gcc -Wall *c -o principal
Creio que assim que é feita a compilação de todos ao mesmo tento ?


Sim. Resolveu?

Só que, fazendo assim, você mata a principal vantagem da compilação em separado, que é economizar tempo de não ter de recompilar código que não foi alterado desde a última compilação.

A maneira tradicional de fazer pode ser entendida através de um exemplo: suponha que você tem um programa que implementa uma um minissistema de notas fiscais, que, além de interagir com o usuário no console, também se comunica por rede usando um protocolo proprietário e grava dados numa base de persistência com um formato também criado pela sua empresa.

Possivelmente você dividiria esse programa em quatro grandes blocos de códigos correlatos: um para implementar o protocolo de comunicação por rede, um para as operações sobre o repositório de dados, um para a interface com o usuário, e um quarto bloco que conteria a inteligência do seu sistema, recorrendo eventualmente a operações providas pelos três primeiros.

Além dessa divisão macro, cada bloco seria dividido em duas partes: uma que especifica a interface que ficará visível para outros módulos que porventura usem as operações que ele provê, e outra que contém a implementação de tais operações. No caso do C e do C++, a interface geralmente fica contida em arquivos de cabeçalhos (em Inglês, headers, de onde vem o sufixo “.h” usualmente empregado nos nomes de tais arquivos), que contém apenas as declarações de símbolos globais, macros e definições de tipos de dados, e não provocam geração de código executável. Essas definições são geralmente suficientes para que o compilador conheça os tipos de cada símbolo, e faça as verificações necessárias para garantir que, quando o símbolo for usado, o será de uma maneira válida e consistentes. Já a implementação, que contém a definição dos símbolos (variáveis e funções), é usado para produzir código executável. Tal código não precisa ser visível para outras partes durante a etapa de compilação, mas somente no momento final da produção do executável, chamada de ligação u linking, quando todos os nomes de símbolos são finalmente trocados por um endereço bem determinado dentro do programa executável.

Assim dividido, seu programa conteria os seguintes arquivos (os nomes são arbitrários):

  • para o protocolo de comunicação, netcomm.h (interface) e netcomm.c (implementação);
  • para a interface com o usuário, userui.h (interface) e userui.c (implementação);
  • para a persistência de dados, companydb.h (interface) e companydb.c (implementação);
  • para a inteligência do sistema, integração das partes, e programa principal, invoice.c (não precisa de interface, porque as operações que ele traz não serão usadas por outros módulos).

Para produzir o executável (chamado, digamos, invoice.bin), você teria que usar o código objeto produzido pelos quatro arquivos “.c”, mas a transformação de cada arquivo “.c” em código objeto poderia ser feita independentemente dos demais. Uma vez que as interfaces de cada módulo tenham atingido a maturidade (isto é, você não vai mais mudar a forma de nenhuma função ou símbolo exportado pela interface visível de nenhum dos módulos), mudanças que tenham de ser feitas na implementação de um módulo (tais como, por exemplo, correções de bugs ou pequenas evoluções de versão) não impactarão o código objeto dos demais módulos, de modo que, para gerar a nova versão do executável, basta recompilar o módulo alterado e refazer o linking dos códigos objetos dos módulos que já estavam prontos com aquele que acabou de ser recompilado.

Esse processo é relativamente simples e fácil de automatizar. Programas como o make ou a configuração de “projetos” oferecidas por ambientes de desenvolvimento integrados permitem definir regras de composição de cada executável a partir de arquivos de objeto e bibliotecas, bem como para a formação de tais objetos e bibliotecas a partir de código fonte em C e C++. Se a data de um arquivo qualquer na cadeia de regras de composição for posterior à do executável já existente, a ferramenta de automatização automaticamente dispara a compilação das partes necessárias ao longo da cadeia, até gerar o(s) executável(is) finais.

No nosso exemplo, um possível conteúdo de arquivo Makefile (que serve como definição de regras para o make) seria algo como o seguinte.

# Variável contendo a lista de arquivos objetos (esses são os produtos
# da compilação de cada arquivo fonte com sufixo “.c”).
OBJECTS=invoice.o companydb.o netcomm.o userui.o

# Além dos objetos produzidos por você pode haver outros objetos ou bibliotecas
# do sistema dos quais seu programa possa depender; Vou supor que netcomm.o
# depende da libresolv, e que userui.c depende da libcurses.
LIBS=-lresolv -lcurses

# Regra genérica para transformar arquivos fontes com sufixo “.c” em arquivos
# objeto com sufixo “.o”. O compilador é chamado com a opção “-c”, que serve
# para apenas compilar os arquivos fontes, sem invocar o linker. O nome do arquivo
# fonte é inferido pelo comando make, e é colocado na linha de comando através
# da variável “$<”.
.c.o:
gcc -Wall -Werror -O2 -pedantic-errors -c $<

# Regra default (que é executada quando se digita apenas “make”), que é a primeira
# regra não-genérica do arquivo, é compilar e ligar todos os executáveis (no nosso
# caso, temos um executável só, então dará na mesma usar “make”, “make all” ou
# “make invoice.bin”.
all: invoice.bin

# Regra específica para gerar “invoice.bin” a partir dos objetos (aqui, o comando gcc
# é usado na função de front-end para o linker, porque o linker padrão do sistema (ld)
# tem uma sintaxe muito mais complexa, que não convém explicar aqui. “$>” significa
# todos os membros da lista de dependências (no caso, é idêntico a $(OBJECTS)), e
# “$@” é o nome do alvo da regra (no caso, “invoice.bin”).
invoice.bin: $(OBJECTS)
gcc -Wall -Werror $> $(LIBS) -o $@







Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts