expr.hpp
typedef int (*evaluate)(PExp);
typedef void (*printTo)(PExp, FILE *);
typedef void (*Exp_free)(PExp);
class Expression {
public:
virtual int evaluate() abstract;
virtual void printTo(FILE * out) abstract;
virtual void free();
};
class Value : public Expression {
protected:
int value;
Value(int value);
public:
int evaluate();
};
Expression.h
#include <stdlib.h>
#include <stdio.h>
typedef struct expression Expression;
typedef Expression * PExp;
typedef int (*evaluate)(PExp);
typedef void (*printTo)(PExp, FILE *);
typedef void (*Exp_free)(PExp);
typedef struct {
evaluate exp_evaluate;
printTo exp_printTo;
Exp_free exp_free;
} vTable;
struct expression {
vTable * v;
};
void expression_init(PExp this);
void exp_free(PExp this);
Value.h
#include "Expression.h"
typedef struct {
Expression super;
int value;
} Value;
void value_init(Value * this, int value);
int value_evaluate(Value * this);
Constant.h
typedef struct {
Value super;
} Constant;
void constant_init(Constant * this, int value);
void constant_free(Constant * this);
void constant_printTo(Constant * this, FILE * out);
expr.h
#include "Expression.h"
#include "Value.h"
#include "Constant.h"
main.c
#include "expr.h"
void constant_init(Constant * this, int value) {
_ZN5ValueC2Ei((Value *)this, value);
printf("%d\n", this->super.super.v->exp_evaluate((PExp)this));
this->super.super.v->exp_printTo = (printTo)constant_printTo; // MARK
}
void constant_printTo(Constant * this, FILE * out) {
fprintf(out, "%d", this->super.value );
putchar('\n');
}
I'm currently trying to implement some code which constructs some objects in C while using C++ at the same time. The classes "Expression" and "Value" are given in C++ and I have to implement the class "Constant" which extends "Value" in C. I cannot change anything in the C++ files (including new files) so that's why I call the "Value" constructor by it's mangled name. The question is: I can call the method exp_evaluate which is defined in the class "Value" but when I try to override the method exp_printTo (MARKED line) it always gives me Segmentation Fault, so what am I doing wrong here?. If I try to call the method, instead of trying to assign another value to the function pointer, it terminates as expected because it is a pure virtual method. Here is the makefile showing that "main" is compiled with 3 C++ files and main.c:
main: use-expr.o expr.o main.o
g++ -o use-expr-c use-expr.o expr.o main.o -g
use-expr.o: use-expr.cpp expr.hpp
g++ -Wall -pedantic -g -c use-expr.cpp -g
expr.o: expr.cpp expr.hpp
g++ -Wall -pedantic -g -c expr.cpp -g
main.o: main.c
gcc -Wall -pedantic -std=c99 -g -c -o main.o main.c -g
It all compiles, the only error I get is at runtime.
I hope there's enough information.
Thank you in advance.
I'd suggest you implement a small wrapper (in C++) that calls the C++, and make the function there have C linkage using extern C. This is a far more reliable method than calling mangled C++ names.
If you really want to know what's up, I'm afraid it's time to break out gdb.
Related
This is a simple example that can help me print malloc params value
void *__wrap_malloc(size_t size)
{
printf("My malloc function!\n");
return __real_malloc(size);
}
But I want to use in class method, like that
class A{
public:
void test(int a)
{
printf("%d", a):
}
}
This using type gives an error.
void A::__wrap_test(int a)
{
printf("wrap");
return A::test()
}
Can someone tell me how to use it correctly?
how to use it correctly?
To use at all, you first have to have a symbol. So first move the inline function definition to be non-inline so a symbol may be generated for it. Then you need to find the mangled name of the symbol. So first correct your typos and compile the library to an object file:
// a.hpp
class A {
public:
void test(int a);
};
// a.cpp
#include <stdio.h>
#include "a.hpp"
void A::test(int a) {
printf("%d\n", a);
}
After compilation check the generated mangled symbol name:
$ g++ -c a.cpp && nm a.o
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T _ZN1A4testEi
U printf
So here you can finally get the name of the symbol to wrap: _ZN1A4testEi. Then you can create the wrapped handler.
I am guessing most probably incorrectly that the first argument to a member function will be a pointer to the class - I did no research on the topic and I do not know if this is true. After getting the symbol name, we can write the main program:
// main.cpp
#include "a.hpp"
extern "C" {
void __real__ZN1A4testEi(A *t, int a);
void __wrap__ZN1A4testEi(A *t, int a) {
printf("wrap ");
return __real__ZN1A4testEi(t, a);
}
};
int main() {
A().test(5);
}
and compile&run with:
$ g++ -c -o a.o a.cpp
$ g++ -c -o main.o main.cpp
$ g++ -Wl,--wrap=_ZN1A4testEi a.o main.o -o main.out
$ ./main.out
wrap 5
I have a c++ program which have a Tcl interpreter.
I wrap my functions and add them into Tcl interpreter manually.
Is it possible to wrap and add them by Swig automatically?
Here is the simplified code:
#include <stdio.h>
#include <tcl.h>
class SystemData { // I have a class which link to all the data and function
public:
void print(){
printf("Hello!\n");
};
};
// I wrap the functions manually. But I'm tired to maintain them.
int Hello( ClientData clientData, Tcl_Interp *interp, int argc, const char **argv ) {
SystemData* system = (SystemData*) clientData;
system->print();
}
int main (int argc, char *argv[]) {
Tcl_Interp *interp = Tcl_CreateInterp();;
SystemData* system = new SystemData;
Tcl_CreateCommand( interp, "hello", Hello, (ClientData)system, (Tcl_CmdDeleteProc *)NULL );
Tcl_Eval(interp, "hello"); // I have a Tcl interpreter so that I can call any function in any time
Tcl_DeleteInterp(interp);
}
I have tried to export SystemData to Tcl by Swig:
// swig.cc
#include <stdio.h>
#include <tcl.h>
class SystemData {
public:
void print(){
printf("Hello!\n");
};
};
SystemData* systemData;
int main (int argc, char *argv[]) {
Tcl_Interp *interp = Tcl_CreateInterp();;
systemData = new SystemData;
Tcl_Eval(interp, "load ./swig.so swig");
Tcl_Eval(interp, "puts $systemData");
Tcl_DeleteInterp(interp);
}
My Swig interface:
/* swig.i */
%module swig
%{
/* Put header files here or function declarations like below */
class SystemData;
extern SystemData* systemData;
%}
extern SystemData* systemData;
The compile commands:
swig -tcl swig.i
g++ -fpic -c swig.cc swig_wrap.c -I/usr/local/include
g++ -shared swig.o swig_wrap.o -o swig.so
However, the result of puts $systemData is
NULL
I also tried do not load swig.so
However, the result of puts $systemData is
can't read "systemData": no such variable
Anyone have an idea?
The problem is in the compile commands. My finally commands are:
swig -c++ -tcl swig.i
g++ -fpic -c swig.cc swig_wrap.cxx
g++ -shared swig.o swig_wrap.o -o swig.so
g++ swig.o swig_wrap.o -o swig.out -g -I/usr/local/include -L/usr/local/lib -ltcl8.5
setenv LD_LIBRARY_PATH /usr/local/lib:/usr/local/lib
./swig.out
And the output of above commands are:
swig.i:22: Warning(454): Setting a pointer/reference variable may leak memory.
_906e600000000000_p_SystemData
Here's a simple set of files that reproduce the problem I'm having:
c.h:
void dummy();
c.cpp:
#include <stdio.h>
extern "C" {
#include "c.h"
}
class Bubu {
public:
static Bubu *getInstance() {
if (_instance == NULL) {
_instance = new Bubu;
}
return _instance;
}
private:
static Bubu *_instance;
};
Bubu *_instance = NULL;
void dummy() {
printf("bubu called\n");
Bubu *ptr = Bubu::getInstance();
}
main.cpp:
extern "C" {
#include "c.h"
}
int main() {
dummy();
return 0;
}
When I compile I get this:
g++ -W -Wall -c c.cpp -o c.o
c.cpp: In function ‘int bubu()’:
c.cpp:24: warning: unused variable ‘ptr’
g++ -W -Wall main.cpp c.o -o main
c.o: In function `Bubu::getInstance()':
c.cpp:(.text._ZN4Bubu11getInstanceEv[Bubu::getInstance()]+0x7): undefined reference to `Bubu::_instance'
c.cpp:(.text._ZN4Bubu11getInstanceEv[Bubu::getInstance()]+0x1d): undefined reference to `Bubu::_instance'
c.cpp:(.text._ZN4Bubu11getInstanceEv[Bubu::getInstance()]+0x24): undefined reference to `Bubu::_instance'
collect2: ld returned 1 exit status
make: *** [main] Error 1
Compilation exited abnormally with code 2 at Tue Dec 15 09:15:21
I've seen the answer to other similar questions but there the problem is either a missing Bubu:: when calling the static method or lack of initialisation of the static member outside the class declaration or missing the extern "C" construct. I'm fairly certain that I'm not making those mistakes ... I'm definitely making other(s).
Can you please explain what's going on?
When you define a static variable inside a class, you have to define it outside the class also. You tried to do this, but
Bubu *_instance = NULL;
will just make a global pointer to Bubu, not instantiate the static one inside the class. You need to use
Bubu *Bubu::_instance = NULL;
to tell the compiler this will be the static variable inside the class.
I am under the impression that you are allowed to define member functions of a class in one file and then use those functions in another file, as long as both files are compiled and sent to the linker. However, doing this gives me an undefined reference error if I use g++ (4.6.4). Interestingly, using the intel compiler (icpc 11.0) does not give an error and everything works. Is there some flag I can set in g++ to make this work, or is the intel compiler letting me get away with something I shouldn't be doing? Here is some code that reproduces my problem:
class.h:
#ifndef _H
#define _H
typedef class
{
public:
int a;
int b;
void set(int x, int y);
int add(void);
} Test;
#endif
class.cpp:
#include "class.h"
void Test::set(int x, int y)
{
a = x;
b = y;
}
int Test::add(void)
{
return a+b;
}
main.cpp:
#include <cstdio>
#include "class.h"
int main(void)
{
Test n;
n.set(3, 4);
printf("%d\n", n.add());
return 0;
}
To compile, I do:
$ g++ class.cpp main.cpp -o test
/tmp/ccRxOI40.o: In function `main':
main.cpp:(.text+0x1a): undefined reference to `Test::set(int, int)'
main.cpp:(.text+0x26): undefined reference to `Test::add()'
collect2: ld returned 1 exit status
Okay, this is strange, but what happened is that this construct:
typedef class
{
public:
int a;
int b;
void set(int x, int y);
int add(void);
} Test;
while legal is not being treated semantically the same by the compiler as:
class Test
{
public:
int a;
int b;
void set(int x, int y);
int add(void);
};
The typedef version makes your methods static to the file, as indicated in the nm output:
$ nm class.o
0000000000000024 t _ZN4Test3addEv
0000000000000000 t _ZN4Test3setEii
U __gxx_personality_v0
While the class Test version makes them proper methods:
$ nm class2.o
0000000000000024 T _ZN4Test3addEv
0000000000000000 T _ZN4Test3setEii
U __gxx_personality_v0
This is why the linker failed to find the symbols.
Edit: As to why this is happening, it seems to be due to an issue with interpreting how the Standard specifies the treatment of the typedef name as a class-name. Newer compilers do not seem to exhibit the same issue. The problem reported in this question was reproduced with g++ 4.4.7.
If you move the code in your class.cpp file into main.cpp and only compile main.cpp, things will work. Alternatively, you can inline the method definitions into class.h.
If you want to leave them as separate translation units, you need to change the class.h file so that your class is defined using the class Test way instead of using the typedef on the anonymous class.
Looked around and found a few similar questions but none of them were the same. Most had to do with the constructor or destructor. This issue is, more than likely, a result of my rusty C++ linker memory (picking it back up after a few years).
I'll keep it real simple since this is probably a basic misunderstanding of the linker:
data.h
#pragma once
namespace test {
class Data_V1 {
public:
// some getters/setters
int getData() { return _d; }
void setData( int d ) { _d = d; }
private:
// some data
int _d;
};
}
builder.h
#pragma once
namespace test {
template <class V>
class Builder {
public:
void build();
};
}
builder.cpp
#include <iostream>
#include "builder.h"
namespace test {
template<class V>
void Builder<V>::build() {
std::cout << "Insert building logic" << std::endl;
}
}
main.cpp
#include "builder.h"
#include "data.h"
using namespace test;
int main(int argc, char* argv[]) {
Builder<Data_V1> b;
b.build();
}
compiling:
g++ -Wall -ansi -pedantic -c builder.cpp
g++ -Wall -ansi -pedantic -c main.cpp
g++ -Wall -ansi -pedantic -o main main.o builder.o
Link error:
Undefined symbols for architecture x86_64:
"test::Builder<test::Data_V1>::build()", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
Any help would be appreciated!
Template definitions need to be visible to all translation units. Move the definition from the cpp to the header.
Builder.h
#pragma once
namespace test {
template <class V>
class Builder {
public:
void build();
};
template<class V>
void Builder<V>::build() {
std::cout << "Insert building logic" << std::endl;
}
}
Before you ask, no, there's no way to hide the implementation unless you know all possible specializations beforehand.
Templates represent a generalized form for the creation of a new class. If the implementation is not visible, when you attempt to specialize the template, the compiler can't know what code to generate.