I'm doing functional testing on c code. Have include .c file in test .cpp file so far, everything works well. But I need to include the same .c file in another .cpp file where I do other unit tests. Then I get problems that is already defined. Because I already include it in the first file cpp.
If merge all the test methods into one cpp file then it works well. If keep all unit test in one file get to big handle so I need to split up diffrent files in same project it also create help functions for secure that functions get in capsules.
This not a normal LNK2005 because I can not declare the variable and functions in .h: as extern BOOL MyBool; and then assign to it in a .c or .cpp file. Because need include c file as I do unit test this function. Also I can't or should avoid do any changes .c.
I looking way to keep include of .c local not effect other files in same project.
source.h
#ifndef SOURCE_H_
#define SOURCE_H_
#include "../car.h"
enum INITIALMODE {
INITIALMODE_NOT_POSITIONING, // 0
INITIALMODE_NO_DRIVER_INPUT, // 1
INITIALMODE_POSITION_LOW_POSITION, // 2
INITIALMODE_POSITION_STANDARD_POSITION, // 3
INITIALMODE_POSITION_HIGH_POSITION // 4
};
void initMotor(void);
#endif
source.c
/* Compiler include files */
#pragma once
#include "positioning.h"
#include "api.h"
#include "drive.h"
#include "types.h"
static void updateTarget(void);
static SWord getMax(UWord Limit, UWord Aux);
static DWord getHeight(void);
static Bool isMode(void);
static Bool isExiting(void);
#define cMaxHeight 100 * Profile.s.Max /* m -> mm */
void initMotor(void)
{
// do something
}
static void updatePositioning(void)
{
// do something
}
Test files look like this, however, this is very scaled for making exemple small.
UnitTest.cpp and UnitTest2.cpp
#include "CppUnitTest.h"
#ifndef UNIT_TEST
#define UNIT_TEST
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace Test
{
extern "C" {
#include "../../Test/source.h"
#include "../../Test/source.c"
}
TEST_CLASS(UnitTest_1)
{
public:
TEST_METHOD(Test_1)
{
// Verify that the initial state is as expected.
initTest();
//Expected value
UWord Expected = 500
//Trigger to execute.
UWord Test = updatePositioning();
// Verify that the results are as expected.
Assert::AreEqual(Expected, Test);
}
};
}
#endif
You should never include a .C or .CPP file.
However, you can compile C code in C++. Here's an example based on the information you gave in your initial post.
YourCCode.h
#ifndef YourCCode_H
#define YourCCode_H
int FunctionToTest(int SomeParams);
int TestStaticFunctions(int SomeParam1, int SomeParam2);
#endif // YourCCode_H
YourCCode.c
#include "YourCCode.h"
static int SomeStaticFunction(int Param1, int Param2)
{
return Param1 + Param2; // that needs extensive testing, obviously.
}
int FunctionToTest(int SomeParams)
{
return SomeStaticFunction(SomeParams, 1);
}
int TestStaticFunctions(int SomeParam1, int SomeParam2)
{
return SomeStaticFunction(SomeParam1, SomeParam2);
}
UnitTest1.cpp
extern "C" {
#include "YourCCode.h"
}
bool TestFunction(int Value)
{
return (FunctionToTest(Value) == Value+1);
}
UnitTest2.cpp
extern "C" {
#include "YourCCode.h"
}
void AnotherTestFunction(int Val, int Val2)
{
int newValue = TestStaticFunctions(Val, Val2);
ASSERT(newValue == Val+Val2);
}
Then compile your CPP and C file.
After you clarified your intent, I realized you're trying to test static functions from another unit. Static function, by definition, are only available to other functions in the same translation unit. This is mostly use as a protection to prevent programmers to call some functions without knowing how to validate their inputs, know the call order, etc...
My best bet here is either you choose that your functions are not static and you can test them from outside your translation unit, or you implement the test functions inside the translation unit containing those static functions. I would recommend the latter as a translation unit should know (architecturally speaking) how to test their own features.
As a third solution, if you don't have any control over the content of the C file (but since you have that C file, I doubt it), you could have a proxy CPP file that includes the C file, and create a proxy call for each static call.
That is a ugly hack, though, and could break very easily if the C file ever gets updated, so I'm advising against it.
Here's a quick example :
YourCCode.h
#ifndef YourCCode_H
#define YourCCode_H
void SomeFunction(void);
#endif // YourCCode_H
YourCCode.c
#include "YourCCode.h"
static int AddSomething(int Param1, int Param2)
{
return Param1 + Param2;
}
static int SubtractSomething(int Param1, int Param2)
{
return Param1 - Param2;
}
void SomeFunction(void)
{
// code meant to be called externally.
}
ProxyTestCode.hpp
bool TestAddSomething(void);
bool TestSubtractSomething(void);
ProxyTestCode.cpp
extern "C" {
#include "YourCCode.h"
#include "YourCCode.c"
}
bool TestAddSomething(void)
{
return (AddSomething(2,2) == 4);
}
bool TestSubtractSomething(void)
{
return (AddSomething(2,2) == 0);
}
UnitTest1.cpp
#include "ProxyTestCode.hpp"
void TestAdd(void)
{
ASSERT(TestAddSomething());
}
UnitTest2.cpp
#include "ProxyTestCode.hpp"
void TestSubtract(void)
{
ASSERT(TestSubtractSomething());
}
If you do that, don't compile your C file in your project.
I am currently working on a virtual run time environment program that is at a very early stage, i am prevented from continuing my work due to a linker error when using my makefile, provided below. The error i am receiving is:
g++ controller.o processor.o test.o -o final
controller.o: In function `Controller::run()':
controller.cpp:(.text+0x1e0): undefined reference to
Processor::codeParams(char)'
controller.o: In function `Controller::fetch()':
controller.cpp:(.text+0x290): undefined reference to `Controller::pc'
controller.cpp:(.text+0x299): undefined reference to `Controller::pc'
collect2: error: ld returned 1 exit status
makefile:16: recipe for target 'final' failed
make: *** [final] Error 1
I am unsure as to why i get this error as i thought i had defined these things in the source file corresponding to the header. All files will be given below so that the program can be compiled.
test.cpp:
#include <iostream>
#include <vector>
#include "includes/controller.h"
using namespace std;
int main()
{
vector<char> prog = {0x0};
Controller contr(prog);
cout << "Error Code: " << contr.run() << endl;
return 0;
}
controller.cpp:
/*
Author(s): James Dolan
File: controller.cpp
Build: 0.0.0
Header: includes/controller.h
DoLR: 21:39 11/1/2017
Todo: n/a
*/
#include "includes/controller.h"
Controller::Controller(vector<char> prog)
{
printf("Program:"); //Display program
for(auto i : program)
{
printf("%02X", i);
}
printf("\n");
Controller::program = program;
}
Controller::~Controller ()
{
}
int Controller::run()
{
bool runFlag = true;
int errorCode = 0;
char curCode;
vector<char> curInstr;
int paramRef;
while(runFlag)
{
curCode = fetch();
printf("curCode:%02X\n", curCode);
curInstr.push_back(curCode);
paramRef = proc.codeParams(curCode);
if (paramRef == 0xffff){runFlag = false; continue;} //Check if shutdown signal was returned, if so shutdown
printf("opcode good\n");
for(int i; i<paramRef; i++){curInstr.push_back(fetch());}
}
return errorCode;
}
char Controller::fetch()
{
return program[pc++]; //Return next instruction then increment the program counter
}
controller.h:
/*
Author(s): James Dolan
File: controller.h
Source: ../controller.cpp
DoLR: 21:39 11/1/2017
Todo: n/a
*/
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <iostream>
#include <vector>
#include <cstdlib>
#include "processor.h"
using namespace std;
class Controller{
public:
Controller(vector<char> prog);
~Controller();
int run();
protected:
private:
vector<char> program;
static int pc;
char fetch();
Processor proc();
};
#endif
processor.cpp:
#include "includes/processor.h"
Processor::Processor()
{
}
Processor::~Processor()
{
}
int codeParams(char code)
{
switch(code)
{
case 0x0: //Halt
return 0;
default:
printf("[ERROR!] Invalid opcode [%02X]", code);
return 0xffff; //Return shutdown signal
}
}
processor.h:
#ifndef PROCESSOR_H
#define PROCESSOR_H
#include <iostream>
#include <cstdlib>
class Processor{
public:
Processor();
~Processor();
int codeParams(char code);
protected:
private:
};
#endif
All if any help is appreciated massively as it will help me to continue with my passion of developing a fully fledged open-source virtual runtime enviroment like the java vm, thank you for your time.
In Controller.cpp you need a int Controller::pc; or int Controller::pc = 0;
In the header file you declared a static int named pc that exists somewhere. It needs to actually exist in a translation unit somewhere (in this case Controller.cpp) so that when the linker tries to find it... it exists.
In Processor.cpp your signature should look like int Processor::codeParams(char code) to let the compiler know that is Processor's codeParams and not a random function named codeParams that happens to also take a character.
For the member function Processor::codeParams you should define it as:
int Processor::codeParams(char code)
// ~~~~~~~~~~~
{
...
}
Otherwise it's just a normal (non–member) function.
For the static member Controller::pc you should define it outside of the class definition, in controller.cpp.
// Controller.h
class Controller {
...
private:
static int pc;
};
// controller.cpp
int Controller::pc;
Let say I've decleared this within MyTools.h
#ifndef _MYTOOLS_
#define _MYTOOLS_
typedef struct {
// const
double LN20;
double LN40;
// methods
double NoteToFrequency(int noteNumber);
} Tool;
extern const Tool tool;
#endif // !_MYTOOLS_
For every compilation unit, there is only a global/const/unique instance of Tool. Exactly what I want.
But now: how can I define it? In the .h i've only declared it. How can I define it in .cpp? Tried somethings like:
tool.LN20 = 1.34;
But of course it doesn't works. And the method's definition?
extern doesn't define any variable it just declares it. What you wan't to achieve can be done as below:
The link Global const object shared between compilation units explains how to do it with extern const
t.h file
#ifndef _MYTOOLS_
#define _MYTOOLS_
struct Tool {
// const
double LN20;
double LN40;
double NoteToFrequency(int noteNumber);
} ;
extern const Tool tool ;
#endif // !_MYTOOLS_
t1.cpp
#include "t.h"
#include <stdio.h>
void use_tool()
{
printf("%f\n",tool.LN20);
printf("%f\n",tool.LN40);
return;
}
t2.cpp
#include "t.h"
#include <stdio.h>
const Tool tool = {.LN20 = 20.0, .LN40 = 30.2};
double Tool::NoteToFrequency(int noteNumber)
{
return 12.0;
}
void use1_tool()
{
printf("%f\n",tool.LN20);
printf("%f\n",tool.LN40);
return;
}
int main()
{
void use_tool();
use_tool();
use1_tool();
return 0;
}
Hope this helps.
What is the best way to initialize a private, static data member in C++? I tried this in my header file, but it gives me weird linker errors:
class foo
{
private:
static int i;
};
int foo::i = 0;
I'm guessing this is because I can't initialize a private member from outside the class. So what's the best way to do this?
The class declaration should be in the header file (Or in the source file if not shared).
File: foo.h
class foo
{
private:
static int i;
};
But the initialization should be in source file.
File: foo.cpp
int foo::i = 0;
If the initialization is in the header file then each file that includes the header file will have a definition of the static member. Thus during the link phase you will get linker errors as the code to initialize the variable will be defined in multiple source files.
The initialisation of the static int i must be done outside of any function.
Note: Matt Curtis: points out that C++ allows the simplification of the above if the static member variable is of const integer type (bool, char, char8_t [since C++20], char16_t, char32_t, wchar_t, short, int, long, long long, or any implementation-defined extended integer types, including any signed, unsigned, and cv-qualified variants.). You can then declare and initialize the member variable directly inside the class declaration in the header file:
class foo
{
private:
static int const i = 42;
};
For a variable:
foo.h:
class foo
{
private:
static int i;
};
foo.cpp:
int foo::i = 0;
This is because there can only be one instance of foo::i in your program. It's sort of the equivalent of extern int i in a header file and int i in a source file.
For a constant you can put the value straight in the class declaration:
class foo
{
private:
static int i;
const static int a = 42;
};
Since C++17, static members may be defined in the header with the inline keyword.
http://en.cppreference.com/w/cpp/language/static
"A static data member may be declared inline. An inline static data member can be defined in the class definition and may specify a default member initializer. It does not need an out-of-class definition:"
struct X
{
inline static int n = 1;
};
For future viewers of this question, I want to point out that you should avoid what monkey0506 is suggesting.
Header files are for declarations.
Header files get compiled once for every .cpp file that directly or indirectly #includes them, and code outside of any function is run at program initialization, before main().
By putting: foo::i = VALUE; into the header, foo:i will be assigned the value VALUE (whatever that is) for every .cpp file, and these assignments will happen in an indeterminate order (determined by the linker) before main() is run.
What if we #define VALUE to be a different number in one of our .cpp files? It will compile fine and we will have no way of knowing which one wins until we run the program.
Never put executed code into a header for the same reason that you never #include a .cpp file.
Include guards (which I agree you should always use) protect you from something different: the same header being indirectly #included multiple times while compiling a single .cpp file.
With a Microsoft compiler[1], static variables that are not int-like can also be defined in a header file, but outside of the class declaration, using the Microsoft specific __declspec(selectany).
class A
{
static B b;
}
__declspec(selectany) A::b;
Note that I'm not saying this is good, I just say it can be done.
[1] These days, more compilers than MSC support __declspec(selectany) - at least gcc and clang. Maybe even more.
int foo::i = 0;
Is the correct syntax for initializing the variable, but it must go in the source file (.cpp) rather than in the header.
Because it is a static variable the compiler needs to create only one copy of it. You have to have a line "int foo:i" some where in your code to tell the compiler where to put it otherwise you get a link error. If that is in a header you will get a copy in every file that includes the header, so get multiply defined symbol errors from the linker.
If you want to initialize some compound type (f.e. string) you can do something like that:
class SomeClass {
static std::list<string> _list;
public:
static const std::list<string>& getList() {
struct Initializer {
Initializer() {
// Here you may want to put mutex
_list.push_back("FIRST");
_list.push_back("SECOND");
....
}
}
static Initializer ListInitializationGuard;
return _list;
}
};
As the ListInitializationGuard is a static variable inside SomeClass::getList() method it will be constructed only once, which means that constructor is called once. This will initialize _list variable to value you need. Any subsequent call to getList will simply return already initialized _list object.
Of course you have to access _list object always by calling getList() method.
C++11 static constructor pattern that works for multiple objects
One idiom was proposed at: https://stackoverflow.com/a/27088552/895245 but here goes a cleaner version that does not require creating a new method per member.
main.cpp
#include <cassert>
#include <vector>
// Normally on the .hpp file.
class MyClass {
public:
static std::vector<int> v, v2;
static struct StaticConstructor {
StaticConstructor() {
v.push_back(1);
v.push_back(2);
v2.push_back(3);
v2.push_back(4);
}
} _staticConstructor;
};
// Normally on the .cpp file.
std::vector<int> MyClass::v;
std::vector<int> MyClass::v2;
// Must come after every static member.
MyClass::StaticConstructor MyClass::_staticConstructor;
int main() {
assert(MyClass::v[0] == 1);
assert(MyClass::v[1] == 2);
assert(MyClass::v2[0] == 3);
assert(MyClass::v2[1] == 4);
}
GitHub upstream.
Compile and run:
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
See also: static constructors in C++? I need to initialize private static objects
Tested on Ubuntu 19.04.
C++17 inline variable
Mentioned at: https://stackoverflow.com/a/45062055/895245 but here is a multifile runnable example to make it even clearer: How do inline variables work?
This awesome C++17 feature allow us to:
conveniently use just a single memory address for each constant
store it as a constexpr: How to declare constexpr extern?
do it in a single line from one header
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
// Both files see the same memory address.
assert(¬main_i == notmain_func());
assert(notmain_i == 42);
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
inline constexpr int notmain_i = 42;
const int* notmain_func();
#endif
notmain.cpp
#include "notmain.hpp"
const int* notmain_func() {
return ¬main_i;
}
Compile and run:
g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main
GitHub upstream.
I don't have enough rep here to add this as a comment, but IMO it's good style to write your headers with #include guards anyway, which as noted by Paranaix a few hours ago would prevent a multiple-definition error. Unless you're already using a separate CPP file, it's not necessary to use one just to initialize static non-integral members.
#ifndef FOO_H
#define FOO_H
#include "bar.h"
class foo
{
private:
static bar i;
};
bar foo::i = VALUE;
#endif
I see no need to use a separate CPP file for this. Sure, you can, but there's no technical reason why you should have to.
You can also include the assignment in the header file if you use header guards. I have used this technique for a C++ library I have created. Another way to achieve the same result is to use static methods. For example...
class Foo
{
public:
int GetMyStatic() const
{
return *MyStatic();
}
private:
static int* MyStatic()
{
static int mStatic = 0;
return &mStatic;
}
}
The above code has the "bonus" of not requiring a CPP/source file. Again, a method I use for my C++ libraries.
The linker problem you encountered is probably caused by:
Providing both class and static member definition in header file,
Including this header in two or more source files.
This is a common problem for those who starts with C++. Static class member must be initialized in single translation unit i.e. in single source file.
Unfortunately, the static class member must be initialized outside of the class body. This complicates writing header-only code, and, therefore, I am using quite different approach. You can provide your static object through static or non-static class function for example:
class Foo
{
// int& getObjectInstance() const {
static int& getObjectInstance() {
static int object;
return object;
}
void func() {
int &object = getValueInstance();
object += 5;
}
};
I follow the idea from Karl. I like it and now I use it as well.
I've changed a little bit the notation and add some functionality
#include <stdio.h>
class Foo
{
public:
int GetMyStaticValue () const { return MyStatic(); }
int & GetMyStaticVar () { return MyStatic(); }
static bool isMyStatic (int & num) { return & num == & MyStatic(); }
private:
static int & MyStatic ()
{
static int mStatic = 7;
return mStatic;
}
};
int main (int, char **)
{
Foo obj;
printf ("mystatic value %d\n", obj.GetMyStaticValue());
obj.GetMyStaticVar () = 3;
printf ("mystatic value %d\n", obj.GetMyStaticValue());
int valMyS = obj.GetMyStaticVar ();
int & iPtr1 = obj.GetMyStaticVar ();
int & iPtr2 = valMyS;
printf ("is my static %d %d\n", Foo::isMyStatic(iPtr1), Foo::isMyStatic(iPtr2));
}
this outputs
mystatic value 7
mystatic value 3
is my static 1 0
Also working in privateStatic.cpp file :
#include <iostream>
using namespace std;
class A
{
private:
static int v;
};
int A::v = 10; // possible initializing
int main()
{
A a;
//cout << A::v << endl; // no access because of private scope
return 0;
}
// g++ privateStatic.cpp -o privateStatic && ./privateStatic
What about a set_default() method?
class foo
{
public:
static void set_default(int);
private:
static int i;
};
void foo::set_default(int x) {
i = x;
}
We would only have to use the set_default(int x) method and our static variable would be initialized.
This would not be in disagreement with the rest of the comments, actually it follows the same principle of initializing the variable in a global scope, but by using this method we make it explicit (and easy to see-understand) instead of having the definition of the variable hanging there.
One "old-school" way to define constants is to replace them by a enum:
class foo
{
private:
enum {i = 0}; // default type = int
enum: int64_t {HUGE = 1000000000000}; // may specify another type
};
This way doesn't require providing a definition, and avoids making the constant lvalue, which can save you some headaches, e.g. when you accidentally ODR-use it.
Here are all possibilities and errors in one simple example ...
#ifndef Foo_h
#define Foo_h
class Foo
{
static const int a = 42; // OK
static const int b {7}; // OK
//static int x = 42; // ISO C++ forbids in-class initialization of non-const static member 'Foo::x'
//static int y {7}; // ISO C++ forbids in-class initialization of non-const static member 'Foo::x'
static int x;
static int y;
int m = 42;
int n {7};
};
// Foo::x = 42; // error: 'int Foo::x' is private
int Foo::x = 42; // OK in Foo.h if included in only one *.cpp -> *.o file!
int Foo::y {7}; // OK
// int Foo::y {7}; // error: redefinition of 'int Foo::y'
// ONLY if the compiler can see both declarations at the same time it,
// OTHERWISE you get a linker error
#endif // Foo_h
But better place this in Foo.cpp. This way you can separately compile each file and link them later, otherwise Foo:x will be present in multiple object files and cause a linker error. ...
// Foo::x = 42; // error: 'int Foo::x' is private, bad if Foo::X is public!
int Foo::x = 42; // OK in Foo.h if included in only one *.cpp -> *.o file!
int Foo::y {7}; // OK
Does this serves your purpose?
//header file
struct MyStruct {
public:
const std::unordered_map<std::string, uint32_t> str_to_int{
{ "a", 1 },
{ "b", 2 },
...
{ "z", 26 }
};
const std::unordered_map<int , std::string> int_to_str{
{ 1, "a" },
{ 2, "b" },
...
{ 26, "z" }
};
std::string some_string = "justanotherstring";
uint32_t some_int = 42;
static MyStruct & Singleton() {
static MyStruct instance;
return instance;
}
private:
MyStruct() {};
};
//Usage in cpp file
int main(){
std::cout<<MyStruct::Singleton().some_string<<std::endl;
std::cout<<MyStruct::Singleton().some_int<<std::endl;
return 0;
}
I just wanted to mention something a little strange to me when I first encountered this.
I needed to initialize a private static data member in a template class.
in the .h or .hpp, it looks something like this to initialize a static data member of a template class:
template<typename T>
Type ClassName<T>::dataMemberName = initialValue;
I am creating programs using C. However, I require to use a lot of libraries that have API's only for C++. So, is it possible that I can create a shared object in C++ and then access its functionality using C?
The only data I would be passing and returning would be C compatible data types.
Converting or migrating to cpp is not an option here.
If it is not possible to interface these codes, how do I get information from C++ code to C code?
I tried calling C++ functions from C, but I get errors during linking when I include <string>. So when I call C++ functions from C, should I only use that code which will be C compiler compatible?
C++ header cppfile.hpp
#ifndef CPPFILE_H
#define CPPFILE_H
#ifdef __cplusplus
extern "C" {
#endif
extern int myfunction(const char *filename);
#ifdef __cplusplus
}
#endif
#endif
C++ file cppfile.cpp
#include "cppfile.hpp"
#include <string>
int myfunction(const char *filename) {
String S(filename);
return 0;
}
C file cmain.c
#include "cppfile.hpp"
int main(int argc, char **argv)
{
int i = myfunction(argv[1]);
printf("%d\n", i);
return 0;
}
Compiling:
gcc -c cmain.c
g++ -fPIC -shared -o cppfile.so cppfile.cpp
You want something more like this (and here I will use a slightly more meaningful example):
C/C++ header - animal.h
#ifndef ANIMAL_H
#define ANIMAL_H
#ifdef __cplusplus
class Animal {
public:
Animal() : age(0), height(0) {}
Animal(int age, float height) : age(age), height(height) {}
virtual ~Animal() {}
int getAge();
void setAge(int new_age);
float getHeight();
void setHeight(float new_height);
private:
int age;
float height; // in metres!
};
#endif /* __cplusplus */
#ifdef __cplusplus
extern "C" {
#endif
struct animal; // a nice opaque type
struct animal *animal_create();
struct animal *animal_create_init(int age, float height);
void animal_destroy(struct animal *a);
void animal_setage(struct animal *a, int new_age);
void animal_setheight(struct animal *a, float new_height);
int animal_getage(struct animal *a);
float animal_getheight(struct animal *a);
#ifdef __cplusplus
}
#endif
#endif /* ANIMAL_H */
C++ animal implementation file - animal.cpp
#include "animal.h"
#define TO_CPP(a) (reinterpret_cast<Animal*>(a))
#define TO_C(a) (reinterpret_cast<animal*>(a))
void Animal::setAge(int new_age) { this->age = new_age; }
int Animal::getAge() { return this->age; }
void Animal::setHeight(float new_height) { this->height = new_height; }
float Animal::getHeight() { return this->height; }
animal *animal_create() {
animal *a = TO_C(new Animal);
return a;
}
animal *animal_create_init(int age, float height) {
animal *a = TO_C(new Animal(age, height));
return a;
}
void animal_destroy(animal *a) {
delete TO_CPP(a);
}
void animal_setage(animal *a, int new_age) {
TO_CPP(a)->setAge(new_age);
}
void animal_setheight(animal *a, float new_height) {
TO_CPP(a)->setHeight(new_height);
}
int animal_getage(animal *a) {
TO_CPP(a)->getAge();
}
float animal_getheight(animal *a) {
TO_CPP(a)->getHeight();
}
C client code - main.c
#include "animal.h"
#include <stdio.h>
int main()
{
// 6'0" 25yo (perhaps a human? :P)
struct animal *a = animal_create(25, 1.83);
animal_setage(a, 26); // birthday
printf("Age: %d\nHeight: %f", animal_getage(a), animal_getheight(a));
animal_destroy(a);
return 0;
}
C++ client code - main.cpp
#include "animal.h"
#include <iostream>
int main()
{
// 6'0" 25yo (perhaps a human? :P)
Animal* a = new Animal(25, 1.83);
a->setAge(26); // birthday
std::cout << "Age: " << a->getAge() << std::endl;
std::cout << "Height: " << a->getHeight();
delete a;
return 0;
}
So when you compile the library, you compile animal.cpp with a C++ compiler. You can then link to it with C code, and use the animal_xxx functions.
Note the use of struct animal and Animal. Animal is a normal C++ type. It's exactly what it looks like. struct animal, on the other hand, is an "opaque" type. That means that your C program can see it's there, and can have one, but it doesn't know what is inside it. All it knows is that it has a function that takes a struct animal*.
In a real library you will want to have customisation points for memory allocation. So assuming this is the library libjungle, you probably want at least jungle_setmalloc and jungle_setfree with sensible defaults. You can then set up the global new and delete in libjungle's C++ code to use these user-defined functions.
This is entirely possible. Here is how, quickly:
1.) You have a header.h with a C API that doesn't include any Cplusiness.
#ifndef MIXEDCCPP_H
#define MIXEDCCPP_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h> // Any C-compatible headers will go here.
// C API goes here. C Functions can't contain any CPPiness.
void myclass_setName( void *pClassObj, const char *pName, int nameLen );
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
// Stuff that is only compatible with CPP goes here
// __cplusplus section won't get processed while compiling C files.
#include <vector> // CPP headers.
class MyClass {
// Classes etc.
};
#endif // #ifdef __cplusplus
#endif // MIXEDCCPP_H
Then in the .cpp, you simply create some C-API functions that can even include CPP right in them:
#include "mixedccpp.h"
extern "C" {
// C API goes here. C Functions can't contain any CPPiness in their prototypes.
void myclass_setName( void *pClassObj, const char *pName, int nameLen )
{
// But CPP knowledge can go inside the function - no problem, since this is a CPP file.
MyClass *pMyClass = static_cast<MyClass *>(pClassObj);
pMyClass->setName( pName, nameLen );
}
} // #extern "C"
// CPP Stuff goes here... or vice-versa.
In your case, you don't actually need any CPP code declared in your header since you are calling external libraries. But you need to create C-compatible functions in your CPP file which can call out to CPP libraries. Use extern "C" for those functions that need to be called from C files, and then use C-structs instead of classes and, if classes are needed, use void * to point to them and then cast them back to their class from the C function any time you need to access them. A standard makefile should be able to compile this just fine, assuming it compiles .cpp files as .cpp and understands extern "C" {}
Your C code cannot use the C++ header <string>. You have to ensure that the functions in the C++ API that are to be called from C are declared extern "C" (as you have), and use only types recognized by a C compiler (as you have).
You also need to link with the C++ compiler if any of your code is in C++. You can do it otherwise if you're prepared to spend a lot of energy getting the loader options right, but it is far simpler just to use the C++ compiler:
gcc -c cmain.c
g++ -fPIC -shared -o cppfile.so cppfile.cpp
g++ -o cmain cmain.o cppfile.so
Of course, you need to:
Add #include <stdio.h> in cmain.c.
Use std::string S(filename); in cppfile.cpp.
Also, if the program is invoked without arguments, you get:
$ ./cmain
terminate called throwing an exceptionAbort trap: 6
$ ./cmain x3
0
$
You need to protect against misuse, even in test programs.