Programinha bem basico em c++ que não compila. Duvidas.

Iniciado por kupfernikel, 16 de Setembro de 2012, 23:13

tópico anterior - próximo tópico

kupfernikel

Ola.
Sou estudante de ciencia da computação e a pouco tempo estou usando ubuntu 12.04 para fazer os trabalhos de programação. O problema é que não estou conseguindo compilar um programa de maneira alguma na minha maquina, mas ele funcionou na maquina do laboratorio de informatica da faculdade! O erro e os codigos estao na imagem abaixo:

http://imgur.com/a/8BdKQ

O codigo esta dois comentarios abaixo

Darcamo

Pelo que vi todos os erros são de referência indefinida, o quer quer dizer que com respeito a sintaxe o programa está correto e compilou normalmente. O problema foi na hora da linkagem. Referência indefinida ocorre quase sempre quando você declara uma função mas não a implementa ou quando usa uma biblioteca externa mas não linka o seu programa com ela (você até diz para o compilador onde encontrar os headers, senão ele sequer compilaria, só não diz para o linkador para linkar seu programa com a tal biblioteca).

Não li o seu programa, apenas olhei as mensagens de erro.
Mas cara, posta o código e as mensagens de erro aqui. Não coloca simplesmente imagens.
Assim podemos tentar compilar aqui e fica mais fácil ajudar.
Além disso fica a referência para caso no futuro alguém tenha dúvidas parecidas. Com apenas um link para as imagens isso não ocorre.

kupfernikel

#2
ok, foi mal o link das imagens, estou no trabalho agora mas assim que chegar em casa vou editar esse post botando o código! Primeira postagem aqui, desculpa o erro de noob heheh.

Estou tentando fazer uma pilha.

Ai vai todos os codigos:

Dado.h

#ifndef _DADO_H_
#define _DADO_H_


class Dado {
int  a;
public:

Dado () {a = 0;};
~Dado () {};
int getDado(){return a;};
void setDado(int b){a=b;};
};
#endif



Node.h
#ifndef _NODE_H_
#define _NODE_H_
#include "Dado.h"

class Node {
private:
Dado d;
public:
Node * Next;
Node() {};
~Node() {};
static Node * montaNo (Dado _D);
static Dado desmontaNo (Node * _P);
void setDado (Dado _pD);
void setNode (Node *_ptr_Next);
};
#endif


Node.cpp
#include "Node.h"

Node * Node::montaNo (Dado _D) {
Node * P = new Node;
if (P) {
P -> d = _D;
P -> Next = NULL;
}
return P;
}

Dado Node::desmontaNo (Node * _P) {
Dado D = _P -> d;
delete _P;
return D;
}

/*
void Node::setDado (Dado _pD) {
d = _pD;
}

void Node::setNode (Node *_ptr_Next) {
Node::Next = _ptr_Next;
}*/

Stack.h
#ifndef _STACK_H_
#define _STACK_H_
#include "Node.h"
#include "Dado.h"
#include <iostream>

class Stack {
private:
Node * TOP;
public:
bool Push(Dado D);
Dado * Pop();
Stack() {TOP = NULL; };
~Stack() {};
//bool TaVazia(int *Top);
//void setTop(int *pTop);
};
#endif


Stack.cpp

#include "Stack.h"

bool Stack::Push (Dado D) {
Node * P = Node::montaNo(D);
if (P) { // if (P != NULL); if (P != 0)
P -> Next = TOP;
TOP = P;
return true;
}
return false;
}

Dado * Stack::Pop () {
if (TOP) {
Node * P = TOP;
TOP = P -> Next; //TOP -> Next;
Dado * D = new Dado;
* D = Node::desmontaNo(P);
return D;
}
return NULL;
}


Main.cpp
#include <iostream>
#include "Stack.h"
using namespace std;


int main () {
int a;
cout << "Digite os dados: \n";
cin >> a;
Dado A;

A.setDado(a);
Stack Pilha;
cout<<A.getDado()<<endl;

Pilha.Push(A);


return 0;
}


E por ultimo o terminal, o erro e o comando que usei :

rafael@rafael-HP:~/prog/Pilha$ g++ main.cpp -o main
/tmp/ccflRrpA.o: In function `main':
main.cpp:(.text+0xa2): undefined reference to `Stack::Push(Dado)'
collect2: ld returned 1 exit status


Obs, usando o GCC acontece isso


rafael@rafael-HP:~/prog/Pilha$ gcc main.cpp -o main
/tmp/cckWDduQ.o: In function `main':
main.cpp:(.text+0x15): undefined reference to `std::cout'
main.cpp:(.text+0x1a): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
main.cpp:(.text+0x29): undefined reference to `std::cin'
main.cpp:(.text+0x2e): undefined reference to `std::basic_istream<char, std::char_traits<char> >::operator>>(int&)'
main.cpp:(.text+0x71): undefined reference to `std::cout'
main.cpp:(.text+0x76): undefined reference to `std::basic_ostream<char, std::char_traits<char> >::operator<<(int)'
main.cpp:(.text+0x7e): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
main.cpp:(.text+0x86): undefined reference to `std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))'
main.cpp:(.text+0xa2): undefined reference to `Stack::Push(Dado)'
/tmp/cckWDduQ.o: In function `__static_initialization_and_destruction_0(int, int)':
main.cpp:(.text+0x127): undefined reference to `std::ios_base::Init::Init()'
main.cpp:(.text+0x12c): undefined reference to `std::ios_base::Init::~Init()'
/tmp/cckWDduQ.o:(.eh_frame+0xeb): undefined reference to `__gxx_personality_v0'
collect2: ld returned 1 exit status

fpissarra

Só adicionei um include (de stdlib.h) para prover a constante NULL, em Node.h e compilou legalzinho...

Mas, vc tem que compilar assim:

$ g++ -c *.cpp
$ g++ -o main Main.o Stack.o Node.o


Compilar só o Main.cpp não vai adiantar nada!

[]s
Fred

Darcamo

#4
Como o fpissarra disse, é necessário adicionar o include de stdlib.h em Node.h para prover a constante NULL.

Mas agora vamos as explicações.

O arquivo Main.cpp inclui o arquivo Stack.h. Se você compilar apenas o arquivo Main.cpp o compilador vai achar o header Stack.h (que está na mesma pasta que Main.cpp), e vai conseguir compilar o Main.cpp normalmente. No entanto, na hora da linkagem o linkador vai sentir falta da implementação de Stack e vai dar erros de undefined reference.

Claro que se você compilar apenas a main e a stack você obterá o mesmo problema com relação a dado e node. Ou seja, você precisa compilar todos os cpps para que na hora da linkagem o linkador tenha todas as implementações de que precisa.

O comando que o fpissarra passou faz isso, mas quebra a compilação e a linkagem em dois passos.
g++ -c *.cpp
apenas compila, criando os arquivos objeto .o, enquanto que o comando
g++ -o main Main.o Stack.o Node.o
(note que o comando acima poderia ser "g++ -o main *.o")
pega todos esses arquivos .o e finalmente efetua a linkagem para gerar um executável com nome "main".

Se quiser fazer tudo em um passo só basta usar o comando
g++ -o main *.cpp


ps: A vantagem de quebrar a compilação e a linkagem em dois passos ocorre quando você modifica um dos arquivos. Assim você precisaria recompilar apenas o arquivo modificado para gerar o novo arquivo ".o" e repetir a linkagem. Claro que fazer isso manualmente quando se tem vários arquivos fica mais complicado. Nessas horas é que algum mecanismo que facilite todo esse processo se torna importante. Um dos mecanismos mais clássicos e usados é o programa "make", que requer que você crie um arquivo chamado "Makefile" para funcionar. Grande parte das IDEs criam um Makefile para você e usam o make para automatizar o processo de compilação e linkagem, mas não é muito complicado criar um Makefile na mão e você deveria evitar essas facilidades de IDE até entender bem como a coisa funciona.

Nesse tópico http://ubuntuforum-pt.org/index.php/topic,21155.0.html fala como criar um Makefile, mas olha só mais para frente para não ficar informação de mais de uma só vez.