Sign in to follow this  

I can't get files linked properly

This topic is 3842 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I can never seem to get these right, but I can't see any difference from other projects. When I try and compile I get linker errors, here are my pages: ERROR
Deleting intermediate and output files for project 'Scripting', configuration 'Debug|Win32'
Compiling...
Implementations.cpp
main.cpp
Generating Code...
Linking...
main.obj : error LNK2019: unresolved external symbol "public: void __thiscall VirtualMachine::Execute(unsigned int)" (?Execute@VirtualMachine@@QAEXI@Z) referenced in function _main
C:\Documents and Settings\Nate\My Documents\Visual Studio 2005\Projects\Scripting\Debug\Scripting.exe : fatal error LNK1120: 1 unresolved externals
Build log was saved at "file://c:\Documents and Settings\Nate\My Documents\Visual Studio 2005\Projects\Scripting\Scripting\Debug\BuildLog.htm"
Scripting - 2 error(s), 0 warning(s)
========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========

Declarations.h
#ifndef DECLARATIONS_H
#define DECLARATIONS_H

#include <vector>

enum opcode
{
	op_talk, 
	op_end 
};

// the basic instruction, currently just encapsulating code
class Instruction
{
private:
	opcode		_code;
	//char*		_data; // additional data, currently not used

public:
	Instruction(opcode code) : _code(code) {}
	opcode Code() const { return _code; }
};

// the basic script, currently just encapsulating an arrayed list of instructions
class Script
{
private:
	std::vector<Instruction> _instrList;

public:
	Script(const std::vector<Instruction>& instrList) : _instrList(instrList) {}
	const Instruction* InstrPtr() const { return &_instrList[0]; }
};

// rudimentary virtual machine wiht methods inlined for convenience
class VirtualMachine
{
private:	// useful abstractions
	// pointers used as non-modifying dynamic references
	typedef const Script*		ScriptRef;
	typedef const Instruction*	InstrRef;

private:	// data members
	std::vector<Script>	_scriptList;
	ScriptRef			_scriptPtr;		// current script
	InstrRef			_instrPtr;		// root instruction
	InstrRef			_instr;			// current instruction
	size_t				_scriptCount;	// track the loaded scripts

private:	// utilities
	size_t AddScript(const Script& script);	// add script to list and retrieve id
	void SelectScript(size_t index);		// set current script by id

public:
	VirtualMachine() : _scriptPtr(0), _instrPtr(0), _instr(0), _scriptCount(0) {}
	// a very basic interface
	inline void Execute(size_t scriptId);
	size_t Load(const Script& script)	{ return AddScript(script); }

};

#endif


Implementations.cpp
#include "Declarations.h"
#include <iostream>
#include <cassert>

size_t VirtualMachine::AddScript(const Script& script)
{
	_scriptList.push_back(script);
	return _scriptCount++;
}

void VirtualMachine::SelectScript(size_t index)
{
	assert(index < _scriptCount);	// make sure the id is valid
	_scriptPtr = &_scriptList[index];
	_instrPtr = _scriptPtr->InstrPtr();
}

void VirtualMachine::Execute(size_t scriptId)
{
	SelectScript(scriptId);		// select our _instrPtr by scriptId
	_instr = _instrPtr;			// set out iterator to beginning
	while(_instr)
	{
		switch(_instr->Code())
		{
		case op_talk:
			std::cout << "I am talking." << std::endl;
			++_instr;	// iterate
			break;
		case op_end:
			_instr = 0;	// discontinue the loop
			break;
		}
	}
}

main.cpp
#include "Declarations.h"

int main()
{
	VirtualMachine vm;

	// build the script
	std::vector<Instruction> InstrList;
	InstrList.push_back(Instruction(op_talk));	// talk twice
	InstrList.push_back(Instruction(op_talk));
	InstrList.push_back(Instruction(op_end));	// then end
	Script script(InstrList);

	// load the script and save the id
	size_t scriptID = vm.Load(script);

	// execute the script by its id
	vm.Execute(scriptID);
}

Share this post


Link to post
Share on other sites
When the compiler compiles main.cpp, Execute is declared as inline but no function definition is provided. Either move the function definition to the header or don't make it inline.

Share this post


Link to post
Share on other sites
Also, why won't this work? Nothing is being printed to the screen now that I've added the char data. Here's the source again, all in one file this time:

main.cpp

#include <vector>
#include <cassert>
#include <iostream>

enum opcode
{
op_talk,
op_print, <---------- ADDED
op_end
};

// the basic instruction, currently just encapsulating code
class Instruction
{
private:
opcode _code;
char* _data; // additional data, currently not used <--------- ADDED

public:
Instruction(opcode code) : _code(code), _data(0) {}
Instruction(opcode code, const char* data, size_t dataSize) : _code(code), _data(new char[dataSize]) { memcpy(_data, data, dataSize); } <--------- ADDED
~Instruction() { delete[] _data; } <---------- ADDED

opcode Code() const { return _code; }
const char* Data() const { return _data; } // read the data <----------- ADDED
};

// the basic script, currently just encapsulating an arrayed list of instructions
class Script
{
private:
std::vector<Instruction> _instrList;

public:
Script(const std::vector<Instruction>& instrList) : _instrList(instrList) {}
const Instruction* InstrPtr() const { return &_instrList[0]; }
};

// rudimentary virtual machine wiht methods inlined for convenience
class VirtualMachine
{
private: // useful abstractions
// pointers used as non-modifying dynamic references
typedef const Script* ScriptRef;
typedef const Instruction* InstrRef;

private: // data members
std::vector<Script> _scriptList;
ScriptRef _scriptPtr; // current script
InstrRef _instrPtr; // root instruction
InstrRef _instr; // current instruction
size_t _scriptCount; // track the loaded scripts

private: // utilities
size_t AddScript(const Script& script); // add script to list and retrieve id
void SelectScript(size_t index); // set current script by id

public:
VirtualMachine() : _scriptPtr(0), _instrPtr(0), _instr(0), _scriptCount(0) {}
// a very basic interface
inline void Execute(size_t scriptId);
size_t Load(const Script& script) { return AddScript(script); }

};

size_t VirtualMachine::AddScript(const Script& script)
{
_scriptList.push_back(script);
return _scriptCount++;
}

void VirtualMachine::SelectScript(size_t index)
{
assert(index < _scriptCount); // make sure the id is valid
_scriptPtr = &_scriptList[index];
_instrPtr = _scriptPtr->InstrPtr();
}

void VirtualMachine::Execute(size_t scriptId)
{
SelectScript(scriptId); // select our _instrPtr by scriptId
_instr = _instrPtr; // set out iterator to beginning
while(_instr)
{
switch(_instr->Code())
{
case op_talk:
std::cout << "I am talking." << std::endl;
++_instr; // iterate
break;
case op_print: <------------- ADDED
std::cout << _instr->Data() << std::endl; // print data
++_instr;
break;
case op_end:
_instr = 0; // discontinue the loop
break;
}
}
}

int main()
{
VirtualMachine vm;

// simulate some external data
char* buffer = "this is printed data.";

// build the script
std::vector<Instruction> InstrList;
InstrList.push_back(Instruction(op_talk)); // talk twice
InstrList.push_back(Instruction(op_print, buffer, strlen(buffer)+1));
InstrList.push_back(Instruction(op_end)); // then end
Script script(InstrList);

// load the script and save the id
size_t scriptID = vm.Load(script);

// execute the script by its id
vm.Execute(scriptID);
}



Share this post


Link to post
Share on other sites
It's kind of odd though; compilers usually treat your inline declarations as "not inline" if it doesn't make sense to them. I guess this one slipped by, and your linker choked on it :-).

Share this post


Link to post
Share on other sites
0) Don't use raw char* for this. Use std::string or std::vector<char>, depending on whether or not your data is really string data or a buffer of bytes.

1) You don't have a copy constructor or assignment operator. Instruction is copied using the default (member-wise) copy constructor, which just aliases the underlying pointer. When any of the Instruction instances aliasing the pointer is destroyed, the memory is released. Your data vanishes. Remember the Rule of Three.

2) Stop using raw char* for your data.

3) Use a debugger and step through the execution, you'll be able to examine exactly what goes wrong and when. It will help you isolate the problem better.

4) Stop using raw char* for your data.

Share this post


Link to post
Share on other sites
Thanks jptetrie. I'm following an article, and the author uses the char*, saying that later in the series it will feel more natural to be using char* rather than strings. But, I can't figure out how to step through the debugger with VC++, or much less use the debugger at all. I need to find a tutorial on it, perhaps I'll go back to the microsoft page.

Share this post


Link to post
Share on other sites
Quote:

and the author uses the char*, saying that later in the series it will feel more natural to be using char* rather than strings.

He's wrong. You can use std::string or std::vector<char> (as appropriate) just as naturally, if not more so, since you don't have to be screwing around with all this manual memory management. What article are you reading?

Quote:

I need to find a tutorial on it, perhaps I'll go back to the microsoft page.

It's rather easy; the MSDN pages have some good articles on using the debugger, and Superpig wrote an article here about debugging.

Share this post


Link to post
Share on other sites
Quote:
Original post by jpetrie
He's wrong. You can use std::string or std::vector<char> (as appropriate) just as naturally, if not more so, since you don't have to be screwing around with all this manual memory management. What article are you reading?

It's rather easy; the MSDN pages have some good articles on using the debugger, and Superpig wrote an article here about debugging.


The article is here, about scripting. Thank you for the link!

Share this post


Link to post
Share on other sites

This topic is 3842 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this