Implementing SystemC TLM Testbench Build Fail - c++

I am trying to implement a SystemC basic TLM test bench for an adder module I created using basic simple_initiator_socket and simple_target_socket.
Currently the build is failing and I am having trouble diagnosing why.
Here are the implementations for the three main modules, the adder, the test bench, and the main module that instantiates both and initiates dataflow.
main.cc
#include "systemc.h"
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"
#include "tlm_utils/tlm_quantumkeeper.h"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
#include "test_bench.h"
#include "adder.h"
SC_MODULE(Top)
{
test_bench *tb;
adder *ad;
sc_signal<bool> rst;
Top(sc_module_name name) :
rst("rst")
{
tb = new test_bench("test_bench");
ad = new adder("adder");
tb->socket.bind(ad->socket);
}
};
int sc_main(int argc, char *argv[])
{
Top *top = new Top("Top");
}
test_bench.cc
#define SC_INCLUDE_DYNAMIC_PROCESS
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"
using namespace sc_core;
using namespace std;
using namespace sc_dt;
#include "test_bench.h"
#include <fstream>
#include <iostream>
test_bench::test_bench(sc_module_name name):
sc_module(name), socket("socket")
{
SC_THREAD(run_tests);
}
void test_bench::run_tests()
{
ifstream infile("../adder.golden.dat");
ofstream ofs;
ofs.open("../adder.dat", ofstream::out | ofstream::app);
while(infile >> data[0] >> data[1])
{
tlm::tlm_generic_payload *trans = new tlm::tlm_generic_payload;
sc_time delay = sc_time(10, SC_NS);
trans->set_data_ptr((unsigned char*)data);
socket->b_transport(*trans, delay);
ofs << data[0] << data[1] << data[2];
delete trans;
}
infile.close();
ofs.close();
printf ("Comparing against output data \n");
if (system("diff -w sha1.dat sha1.golden.dat"))
{
cout << "*******************************************" << endl;
cout << "FAIL: Output DOES NOT match the golden output" << endl;
cout << "*******************************************" << endl;
}
else
{
cout << "*******************************************" << endl;
cout << "PASS: The output matches the golden output!" << endl;
cout << "*******************************************" << endl;
}
}
adder.cc
#define SC_INCLUDE_DYNAMIC_PROCESS
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"
using namespace sc_core;
using namespace std;
#include "adder.h"
adder::adder(sc_module_name name)
: sc_module(name), socket("socket")
{
socket.register_b_transport(this, &adder::b_transport);
socket.register_transport_dbg(this, &adder::transport_dbg);
}
void adder::b_transport(tlm::tlm_generic_payload& trans, sc_time& delay)
{
tlm::tlm_command cmd = trans.get_command();
sc_dt::uint64 addr = trans.get_address();
uint32_t *ptr = (uint32_t*)trans.get_data_ptr();
unsigned int len = trans.get_data_length();
unsigned char *byt = trans.get_byte_enable_ptr();
unsigned int wid = trans.get_streaming_width();
addend1 = *ptr;
addend2 = *(ptr++);
add();
memcpy(ptr + sizeof(uint32_t) * 2, (char*) &sum, sizeof(uint32_t));
}
unsigned int adder::transport_dbg(tlm::tlm_generic_payload& trans)
{
return 0;
}
void adder::add()
{
sum = addend1 + addend2;
}
Here is the error I am seeing upon compilation.
In file included from
/home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/sysc/kernel/sc_module.h:35:0,
from /home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/systemc:74,
from /home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/tlm:23,
from /home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/tlm_utils/simple_initiator_socket.h:23,
from /home/test_benches/adder/test_bench.cc:3:
/home/test_benches/adder/test_bench.cc:
In constructor ‘test_bench::test_bench(sc_core::sc_module_name)’:
/home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/sysc/kernel/sc_module.h:463:29:
error: ‘SC_CURRENT_USER_MODULE’ has not been declared
SC_CURRENT_USER_MODULE, \
/home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/sysc/kernel/sc_process.h:151:46: note: in definition of macro ‘SC_MAKE_FUNC_PTR’
static_cast(&callback_tag::func)
/home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/sysc/kernel/sc_module.h:461:5:
note: in expansion of macro ‘declare_thread_process’
declare_thread_process( func ## _handle, \
/home/test_benches/adder/test_bench.cc:17:2: note: in expansion of
macro ‘SC_THREAD’ SC_THREAD(run_tests);
make: ***
[/home//test_benches/adder/obj/test_bench.o]
Error 1
My best guess is that I did not set up the sockets correctly. The test bench has a simple_initiator_socket and the adder has a simple_target_socket. Do I need to register the simple_target_socket with a b_transport method for the module? I did so in the initiator but in the tutorial below I did not see a requirement to do so for the target. My guess was the dataflow was like this:
simple_initiator_socket (member of test_bench) registered to b_transport method of module and simple_target_socket of another module (in top module)
Initiator module (test_bench) sets up tlm_generic_payload with data it needs to send to target (adder)
b_transport method of simple_initiator_socket (member of test_bench) called with tlm_generic_payload being passed (with addends for adder)
Target socket (target) receives and decodes tlm_generic_payload (addend values) that was passed.
Target socket (adder) performs operations (adds decoded addends) and modifies the tlm_generic_payload (passed by value) (by writing the computed sum back to the payload memory)
Initiator (test_bench) looks at modified tlm_generic_payload (now contains sum) and does some process (checks against theoretical sum)
I was trying to follow this example.
https://www.doulos.com/knowhow/systemc/tlm2/tutorial__1/
UPDATE
test_bench.h
class test_bench:
public sc_core::sc_module
{
public:
tlm_utils::simple_initiator_socket<test_bench> socket;
sc_out<bool> irq;
test_bench(sc_core::sc_module_name name);
void run_tests();
private:
uint32_t data[3];
};

There are two ways to declare modules in SystemC.
The first one is through using SC_MODULE macro:
SC_MODULE(mymodule) {
SC_CTOR(mymodule)
{
}
};
And the second one without it:
class mymodule : public sc_core::sc_module {
SC_HAS_PROCESS(mymodule);
public:
mymodule(sc_core::sc_module_name)
{ }
};
I would prefer the second one because:
It avoids those nasty macros as much as possible.
It allows you to inherit from another module.
Now why you need SC_MODULE or SC_HAS_PROCESS macros. The reason is that macros SC_METHOD and SC_THREAD need to know type of module they are being used from to do their job. Since SystemC is based on old revision of C++ language released in 1998, there was no way to do this automatically. So helper macro SC_HAS_PROCESS was defined as:
#define SC_HAS_PROCESS(user_module_name) typedef user_module_name SC_CURRENT_USER_MODULE
This allows SC_METHOD and SC_THREAD to use SC_CURRENT_USER_MODULE as synonym for module they are being used in. Macro SC_MODULE already uses SC_HAS_PROCESS behind the curtain.
Another advise - if you are using C++11 compatible compiler you can declare a helper macro for yourself:
#define DECL(name, ...) name{#name, __VA_ARGS__}
This can help you declare named objects without typing their name twice:
sc_in<bool> DECL(clk);
Any error message mentioning this port with contain proper name for it.
Can also be used in constructor to initialize member field:
mymodule(sc_core::sc_module_name)
: DECL(clk)
{
}

Related

How to pass data through MVC for C++ (possibly using vectors or pointers)

So I have a project in which I must parse a data file, and dynamically create instances of a class Sensor while passing in the parsed data to that class. I am storing these instances in a vector of object pointers, sensors. Once the data is passed into each instance of Sensor, inside the Sensor class I must generate a reading value using the min and max values passed in from the parser. Then all of the values, min, max, type, reading, material, id must be passed to a controller class called SensorMount . This class is responsible for routing the data to a DisplayDeviceclass that I have not yet implemented.
I am confused on how to implement my controller SensorMount class. I know I need to use my get functions in the Sensor class, but I just am not sure where to start with this. Would another vector of Sensor object instances work? That is my current idea but I'm not sure if that is possible. I know sending a "message object" (Stated by my prof) could work but I can't seem to find any implementation of one online. I really appreciate any help and patience, I'm new to this and feel really stuck.
Also, I see alot of people on stack overflow condemn the use of using namespace but my professor wants us to use it. And we are not to implement a design pattern for this program (I know observer would work) , we will do that in the next.
Simulation.cpp (Where data parser is called and vector is created and initial data is passed )
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include "Simulation.hpp"
#include "EnviroSimDataParser.h"
Simulation::Simulation() {}
Simulation::~Simulation(){}
void Simulation::initializeSimulation() {
char fileName[64];
char m_sType[64];
char m_sMaterial[64];
int m_iID;
char m_sUnits[64];
double m_sMinVal;
double m_sMaxVal;
char type[64];
int IDs[8];
int IDCount;
cout << "Enter the name of the data file:" << endl;
cin >> fileName ;
//cout << fileName << "\n" ;
parser = new EnviroSimDataParser(fileName);
for (int i = 0; i < 6; i++){
parser ->getSensorData(m_sType, m_sMaterial, &m_iID, m_sUnits, &m_sMinVal, &m_sMaxVal);
sensors.push_back(new Sensor(m_sType, m_sMaterial, m_iID, m_sUnits, m_sMinVal, m_sMaxVal));
cout << "success " << m_iID << endl;
}
for (int x = 0; x <4; x++){
parser -> getDisplayData(type, IDs, &IDCount);
//if (strcmp(type, ""))
}
mount = new SensorMount();
display = new Display();
}
void Simulation::runSimulation(){
}
Sensor.cpp
#include "Sensor.hpp"
Sensor::Sensor(char *SensorType, char *SensorMaterial, int SensorID, char *SensorUnit, double MaxVal, double MinVal) {
strcpy(type, SensorType);
strcpy(material, SensorMaterial);
ID = SensorID;
strcpy(unit, SensorUnit);
max = MaxVal;
min = MinVal;
}
Sensor::Sensor(){}
Sensor::~Sensor()
{
}
double Sensor::generateReading(){
reading = min + (rand() % (int)(max - min + 1));
cout << reading<< endl;
return reading;
}
char * Sensor::getType(){
return type;
}
char * Sensor::getMaterial(){
return material;
}
int Sensor::getID(){
return ID;
}
char * Sensor::getUnit(){
return unit;
}
double Sensor::getMin(){
return min;
}
double Sensor::getMax(){
return max;
}
double Sensor::getReading(){
return reading;
}
//void Sensor::sendSensorData(){
// SensorMount.routeData(Display)
//}
Sensor.h
#ifndef Sensor_hpp
#define Sensor_hpp
#include <stdio.h>
#include <iostream>
#include <fstream>
using namespace std;
class Sensor
{
public:
Sensor();
Sensor(char *SensorType, char *SensorMaterial, int SensorID, char *SensorUnit, double MaxVal, double MinVal);
~Sensor();
//virtual Sensor updateSensor();
char * getType();
char * getMaterial();
int getID();
char * getUnit();
double getMin();
double getMax();
double getReading();
private:
char type[32];
char material[32];
int ID;
int reading;
char unit[32];
double min;
double max;
double generateReading();
};
#endif /* Sensor_hpp */
SensorMount.h (controller)
#ifndef SensorMount_hpp
#define SensorMount_hpp
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <vector.
#include "Sensor.hpp"
#include "Display.hpp"
using namespace std;
class SensorMount{
private:
Sensor *sensors;
Display *displayDevices;
vectorgetSensorData;
public:
SensorMount();
~SensorMount();
};
#endif /* SensorMount_hpp */

C++ Undeclared Identifier on Object creation

So I am new to c++, coming from C#. This is giving me several errors when compiling, which all seem to relate to this object declaration. Anyone able to show me the right way to do this?
I get an undeclared identifier where i declare tri(sideLength).
I have used this as a reference for object declaration, but it doesn't seem to be helping me.
Thanks.
#include <iostream> // Provides cout
#include <iomanip> // Provides setw function for setting output width
#include <cstdlib> // Provides EXIT_SUCCESS
#include <cassert> // Provides assert function
#include <stdexcept>
#include <math.h>
using namespace std; // Allows all standard library items to be used
void setup_cout_fractions(int fraction_digits)
// Precondition: fraction_digits is not negative.
// Postcondition: All double or float numbers printed to cout will now be
// rounded to the specified digits on the right of the decimal.
{
assert(fraction_digits > 0);
cout.precision(fraction_digits);
cout.setf(ios::fixed, ios::floatfield);
if (fraction_digits == 0)
cout.unsetf(ios::showpoint);
else
cout.setf(ios::showpoint);
}
int main()
{
const int MAX_SIDE_LENGTH = 6;
const int INITIAL_LENGTH = 1;
const int DIGITS = 4;
const int ARRAY_SIZE = 6;
// Set up the output for fractions and print the table headings.
setup_cout_fractions(DIGITS);
// Each iteration of the loop prints one line of the table.
for (int sideLength = 0; sideLength < MAX_SIDE_LENGTH; sideLength += 1)
{
EquilateralTriangle tri(sideLength);
//Square sq(sideLength);
//Pentagon_Reg pent(sideLength);
//Hexagon_Reg hex(sideLength);
//Heptagon_Reg hept(sideLength);
//Octagon_Reg octa(sideLength);
cout << "Type: " << tri.Name() << "has area: " << tri.Area() << " with SideLength = " << sideLength;
}
return EXIT_SUCCESS;
}
//Template
class GeometricFigure
{
public:
GeometricFigure() { }
double SideLength;
virtual double Area() { return 0; };
virtual char* Name() { return ""; };
};
class EquilateralTriangle : public GeometricFigure {
public:
EquilateralTriangle(double sideLength)
{
SideLength = sideLength;
}
char* Name() { return "Equilateral Triangle"; }
double Area() { return (sqrt(3) / 2 * pow(SideLength, 2)); }
};
In C++, the compiler reads your code from top-to-bottom, once. This is a holdover from when early C compilers only had a few kilobytes of memory to work with - C was designed so that a compiler would only need to look at a little bit of the code at a time.
Because of this, things must have been declared or defined as necessary, before you try to use them.
Move both classes somewhere before main. GeometricFigure must be before EquilateralTriangle, and EquilateralTriangle must be before main.
You would need to "declare" or tell the compiler, where to look for the EquilateralTriangle and GeometricFigure, "before" you use it first. you might want to take a look at the similar discussion at - C# declarations vs definitions

Find If-Conditions using Clang

I'm trying to find the if-conditions in a C-code using Clang.
What I've learned till now is to find the declarations using HandleTopLevelDecl().
What I'm trying to do now is to find a function that is similar to HandleTopLevelDecl() but handles the If-Conditions.
My question is, am I on the right path? is there a function that can do this?
And if not, what do you advice me to do?
Thanks.
With the help of this awesome course: http://swtv.kaist.ac.kr/courses/cs453-fall13
Specially this tutorial: http://swtv.kaist.ac.kr/courses/cs453-fall13/Clang%20tutorial%20v4.pdf
I have solved the problem.
I needed to create a RecursiveASTVisitor and handle the If-Statements while visiting the Statements.
class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor>
{
public:
bool VisitStmt(Stmt *s) {
// Search for If-Statements
if(isa<IfStmt>(s))
{
cerr << "Found IF" << endl;
}
return true;
}
bool VisitFunctionDecl(FunctionDecl *f) {
// Print function name
cerr << f->getNameAsString().c_str() << endl;
return true;
}
};
And here are the complete code:
#include <cstdio>
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <utility>
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Rewrite/Frontend/Rewriters.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace std;
// CompilerInstance
CompilerInstance TheCompInst;
class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor>
{
public:
bool VisitStmt(Stmt *s) {
// Search for If-Statements
if(isa<IfStmt>(s))
{
SourceManager &srcmgr = TheCompInst.getSourceManager();
SourceLocation startLocation = s->getLocStart();
unsigned int start_lineNum = srcmgr.getExpansionLineNumber(startLocation);
cerr << "Found IF # Line: " << start_lineNum << endl;
}
return true;
}
bool VisitFunctionDecl(FunctionDecl *f) {
// Print function name
cerr << f->getNameAsString().c_str() << endl;
return true;
}
};
class MyASTConsumer : public ASTConsumer
{
public:
MyASTConsumer()
: Visitor() //initialize MyASTVisitor
{}
virtual bool HandleTopLevelDecl(DeclGroupRef DR) {
for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
// Travel each function declaration using MyASTVisitor
Visitor.TraverseDecl(*b);
}
return true;
}
private:
MyASTVisitor Visitor;
};
int main(int argc, char *argv[])
{
if (argc != 2) {
llvm::errs() << "Usage: kcov-branch-identify <filename>\n";
return 1;
}
// Diagnostics manage problems and issues in compile
TheCompInst.createDiagnostics(NULL, false);
// Set target platform options
// Initialize target info with the default triple for our platform.
TargetOptions *TO = new TargetOptions();
TO->Triple = llvm::sys::getDefaultTargetTriple();
TargetInfo *TI = TargetInfo::CreateTargetInfo(TheCompInst.getDiagnostics(), TO);
TheCompInst.setTarget(TI);
// FileManager supports for file system lookup, file system caching, and directory search management.
TheCompInst.createFileManager();
FileManager &FileMgr = TheCompInst.getFileManager();
// SourceManager handles loading and caching of source files into memory.
TheCompInst.createSourceManager(FileMgr);
SourceManager &SourceMgr = TheCompInst.getSourceManager();
// Prreprocessor runs within a single source file
TheCompInst.createPreprocessor();
// ASTContext holds long-lived AST nodes (such as types and decls) .
TheCompInst.createASTContext();
// A Rewriter helps us manage the code rewriting task.
Rewriter TheRewriter;
TheRewriter.setSourceMgr(SourceMgr, TheCompInst.getLangOpts());
// Set the main file handled by the source manager to the input file.
const FileEntry *FileIn = FileMgr.getFile(argv[1]);
SourceMgr.createMainFileID(FileIn);
// Inform Diagnostics that processing of a source file is beginning.
TheCompInst.getDiagnosticClient().BeginSourceFile(TheCompInst.getLangOpts(),&TheCompInst.getPreprocessor());
// Create an AST consumer instance which is going to get called by ParseAST.
MyASTConsumer TheConsumer;
// Parse the file to AST, registering our consumer as the AST consumer.
ParseAST(TheCompInst.getPreprocessor(), &TheConsumer, TheCompInst.getASTContext());
return 0;
}
There are specific functions in clang for all kinds of Stmts and Decls. For this particular case, it is going to be VisitIfStmt. Check IfStmt being included in RecusiveASTVisitor.h.
RecursiveASTVisitor.h -
#define STMT(CLASS, PARENT) \
bool WalkUpFrom##CLASS(CLASS *S) { \
TRY_TO(WalkUpFrom##PARENT(S)); \
TRY_TO(Visit##CLASS(S)); \
return true; \
} \
bool Visit##CLASS(CLASS *S) { return true; }
#include "clang/AST/StmtNodes.inc"
clang/AST/StmtNodes.inc -
#ifndef IFSTMT
# define IFSTMT(Type, Base) STMT(Type, Base)
#endif
IFSTMT(IfStmt, Stmt)
#undef IFSTMT
These, together create the function VisitIfStmt(IfStmt*) in the class.

C++ several object serialization

So I make a serialization of a single object but I had problem with several.
Here is the code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class MyTest
{
private:
string test;
public:
MyTest():test(""){};
void setTest(const string& test) {this->test = test;};
string getTest() const {return this->test;};
};
void writeToFile(const MyTest& m)
{
ofstream ofs("data.mbp", ios::app|ios::binary);
ofs.clear();
ofs.write((char *)&m, sizeof(m));
ofs.flush();
ofs.close();
return;
};
MyTest& readTest(MyTest& m,int num)
{
ifstream ifs;
ifs.open("data.mbp", ios::in|ios::binary);
for ( int i = 1 ; i <= num ; i++)
ifs.read((char *)&m, sizeof(m));
return m;
}
int main(int argc,char* argv[])
{
MyTest m,t;
m.setTest("Hello");
writeToFile(m);
t.setTest("World");
writeToFile(t);
t = readTest(t,1);
cout << t.getTest() << endl;
m = readTest(m,2);
cout << m.getTest() << endl;
return 0;
}
The problem is that I do not know how to write two or more objects in a binary file and after that how can I read them.
Does anybody know?
Thanks in advance.
I recommend you using Boost - Serialization for serializing objects in C++: http://www.boost.org/libs/serialization/
There are a lot of different ways of doing that. You need to select a file format first. Think about XML in the first hand. Serialization of complex data structures is better to base on some existing library rather than write it yourself from scratch. Search Inet for such libraries.

What is good practice for generating verbose output?

what is good practice for generating verbose output? currently, i have a function
bool verbose;
int setVerbose(bool v)
{
errormsg = "";
verbose = v;
if (verbose == v)
return 0;
else
return -1;
}
and whenever i want to generate output, i do something like
if (debug)
std::cout << "deleting interp" << std::endl;
however, i don't think that's very elegant. so i wonder what would be a good way to implement this verbosity switch?
The simplest way is to create small class as follows(here is Unicode version, but you can easily change it to single-byte version):
#include <sstream>
#include <boost/format.hpp>
#include <iostream>
using namespace std;
enum log_level_t {
LOG_NOTHING,
LOG_CRITICAL,
LOG_ERROR,
LOG_WARNING,
LOG_INFO,
LOG_DEBUG
};
namespace log_impl {
class formatted_log_t {
public:
formatted_log_t( log_level_t level, const wchar_t* msg ) : fmt(msg), level(level) {}
~formatted_log_t() {
// GLOBAL_LEVEL is a global variable and could be changed at runtime
// Any customization could be here
if ( level <= GLOBAL_LEVEL ) wcout << level << L" " << fmt << endl;
}
template <typename T>
formatted_log_t& operator %(T value) {
fmt % value;
return *this;
}
protected:
log_level_t level;
boost::wformat fmt;
};
}//namespace log_impl
// Helper function. Class formatted_log_t will not be used directly.
template <log_level_t level>
log_impl::formatted_log_t log(const wchar_t* msg) {
return log_impl::formatted_log_t( level, msg );
}
Helper function log was made template to get nice call syntax. Then it could be used in the following way:
int main ()
{
// Log level is clearly separated from the log message
log<LOG_DEBUG>(L"TEST %3% %2% %1%") % 5 % 10 % L"privet";
return 0;
}
You could change verbosity level at runtime by changing global GLOBAL_LEVEL variable.
int threshold = 3;
class mystreambuf: public std::streambuf
{
};
mystreambuf nostreambuf;
std::ostream nocout(&nostreambuf);
#define log(x) ((x >= threshold)? std::cout : nocout)
int main()
{
log(1) << "No hello?" << std::endl; // Not printed on console, too low log level.
log(5) << "Hello world!" << std::endl; // Will print.
return 0;
}
You could use log4cpp
You can wrap your functionality in a class that supports the << operator which allows you to do something like
class Trace {
public:
enum { Enable, Disable } state;
// ...
operator<<(...)
};
Then you can do something like
trace << Trace::Enable;
trace << "deleting interp"
1. If you are using g++ you could use the -D flag, this allows the compilator to define a macro of your choice.
Defining the
For instance :
#ifdef DEBUG_FLAG
printf("My error message");
#endif
2. I agree this isn't elegant either, so to make it a bit nicer :
void verbose(const char * fmt, ... )
{
va_list args; /* Used as a pointer to the next variable argument. */
va_start( args, fmt ); /* Initialize the pointer to arguments. */
#ifdef DEBUG_FLAG
printf(fmt, &args);
#endif
/*This isn't tested, the point is to be able to pass args to
printf*/
}
That you could use like printf :
verbose("Error number %d\n",errorno);
3. A third solution easier, and more C++ and Unix like is to pass an argument to your program that is going to be used - as the macro earlier - to initialize a particular variable (that could be a global const).
Example :
$ ./myprogram -v
if(optarg('v')) static const verbose = 1;