How to define a "global" struct? - c++

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.

Related

Include .c files in Unit test project and get access to it from multiple cpp files without linking problems

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.

'ClassName' and 'ClassInstance' was not declared in this scope

I am attempting to program an Atmel SAM D21 microcontroller using C++ in Atmel Studio. I'm trying to create periodic hardware interrupts using one of the on-chip timers.
I created Timer4 class to set up the timer from main.cpp. I tried to create a Timer4 instance called MyTimer4 in the main function, but it says
'Timer4' was not declared in this scope
'MyTimer4' was not declared in this scope
I've seen many similar discussions pointing to incorrect/circular #includes. But, I don't seem to see the same problem on my own. Any ideas?
Main.cpp
#include "timerSAMD21.h"
#include "sam.h"
void SampleADC(void)
{
}
int main(void)
{
SystemInit();
Timer4 MyTimer4;
MyTimer4.setRate(1000);
MyTimer4.onEvent(SampleADC);
MyTimer4.start;
}
timerSAMD21.h
#ifdef TIMERSAMD21_H
#define TIMERSAMD21_H
#include "tc.h"
#include "tc4.h"
#include "gclk.h"
typedef void (*voidFuncPtr)(void);
class Timer4
{
public:
Timer4() {};
void setRate(int frequency);
void start(void);
void end(void);
void onEvent(voidFuncPtr funcOnEvent);
private:
void configure(int frequency);
void enable(void);
void disable(void);
void reset(void);
};
#endif
timerSAMD21.cpp
#include "timerSAMD21.h"
voidFuncPtr callback = NULL;
void Timer4::setRate(int frequency) {
configure(frequency);
}
void Timer4::start(void) {
enable();
}
void Timer4::end(void) {
disable();
reset();
}
void Timer4::configure(int frequency) {
//Configuration code here. Removed for Stack Overflow.
}
void Timer4::enable(void){
REG_TC4_CTRLA |= TC_CTRLA_ENABLE; //Enable timer
while (TC4->COUNT8.STATUS.bit.SYNCBUSY);
}
void Timer4::disable(void) {
REG_TC4_CTRLA &= ~TC_CTRLA_ENABLE;
while (TC4->COUNT8.STATUS.bit.SYNCBUSY);
}
void Timer4::reset(void) {
REG_TC4_CTRLA = TC_CTRLA_SWRST;
while (TC4->COUNT8.STATUS.bit.SYNCBUSY);
while (TC4->COUNT8.CTRLA.bit.SWRST);
}
void Timer4::onEvent(voidFuncPtr funcOnEvent){
callback = funcOnEvent;
}
#ifdef __cplusplus
extern "C" {
#endif
void IRQHandlerTimer4(void) {
if (callback != NULL)
{
callback();
}
REG_TC4_INTFLAG = TC_INTFLAG_MC0;
}
#ifdef __cplusplus
}
#endif
(Note: Making an answer in order to get this out of the list of unanswered questions. Miles seems to have decided not to answer and I do not consider the problem a typo.)
The way you attempt to prevent the reinclusion of your header is causing it to only make the content of the header visible if the guard-macro happens to be defined already, which it of course never is.
In order to fix this, change the
#ifdef TIMERSAMD21_H
#define TIMERSAMD21_H
into
#ifndef TIMERSAMD21_H
#define TIMERSAMD21_H
This will first keep the header content visible the first time it is included.
It will then define the guard macro, which will prevent the header content from being compiled a second time in the same translation unit, i.e. code file.

Call function outside of current namespace in C++

I'm trying to call a function defined in a C file from my CPP code and I think I am having issues getting the correct namespace. When compiling I get the error: "Undefined reference to 'Get'".
My C header:
// c.h
#ifndef C_H
#define C_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum
{
VAL_A1,
VAL_A2
} TYPE_A;
typedef enum
{
VAL_B1,
VAL_B2
} TYPE_B;
typedef enum
{
VAL_C1,
VAL_C2
} TYPE_C;
typedef struct
{
TYPE_B b;
TYPE_C c;
} TYPE_D;
TYPE_A Get(TYPE_B b, TYPE_D *d);
#ifdef __cplusplus
}
#endif
#endif
And my CPP file:
// main.cpp
...
extern "C" {
#include "c.h"
}
...
namespace MyNamespace
{
...
MyClass::MyFunc()
{
TYPE_D d;
// None of these calls will compile
// Get(VAL_B1, &d);
// ::Get(VAL_B1, &d);
}
...
}
I have tried calling without namespace reference and also with the "root" namespace using "::" with no luck. Any help is appreciated. I've read through this which seems to clarify it but I don't really understand it:
using C++ with namespace in C
"Undefined reference" means that the function has been declared (in the header), but not defined. You'll need to define the function in a source file somewhere (presumably the C file you refer to), and make sure that is linked when you build the program.
First, let's note what that error means. An undefined reference at the linker stage means that the compiler is unable to find the instance of something. In this case, the implementation of a function.
Let's look at your code.. There are a few things missing that we need to add to make it compilable:
A definition for Get().
main()
The class definition for MyClass.
Once we added those three fixes, the code compiles without error.
extern "C" { extern "C" {
typedef enum {
VAL_A1,
VAL_A2
} TYPE_A;
typedef enum {
VAL_B1,
VAL_B2
} TYPE_B;
typedef enum {
VAL_C1,
VAL_C2
} TYPE_C;
typedef struct {
TYPE_B b;
TYPE_C c;
} TYPE_D;
TYPE_A Get(TYPE_B b, TYPE_D *d) {
return VAL_A1;
}
}}
namespace MyNamespace {
struct MyClass {
void MyFunc();
};
void MyClass::MyFunc() {
TYPE_D d;
Get(VAL_B1, &d);
::Get(VAL_B1, &d);
}
}
int main() {}
The definition of Get (not shown in the question) also needs to be enclosed in extern "C".
The main difference between C and C++ functions, in practice, is the way they are named in the executable format. C++ functions get "name mangling" treatment by the linker but C functions do not. The linker will see the C++ definition of Get and it will have no idea of its relation to the C declaration, even if they have the same signature.

Can I use shared library created in C++ in a C program?

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.

call a member of a nested structure, ERROR does not have class type

In main.C I am trying to access a nested structure member
(g.Fp1.d_status) and am getting the error:
'g.GridPt::Fp1' does not have class type
Below is my code. I can realy use some help. Thanks.
I tried stuff like g.MarchingDirection::Fp1.d_status,
g.&MarchingDirection::Fp1.d_status, ... with no luck.
//Filename: main.C
#include "GridPt.h"
int main()
{
GridPt g;
g.d_lstDistFn;
g.Fp1.d_status; \\ERROR: 'g.GridPt::Fp1' does not have class type
return 0;
}
//Filename: MarchingDirection.h
#ifndef included_MarchingDirection
#define included_MarchingDirection
struct MarchingDirection
{
MarchingDirection(double FValue);
double d_F;
int d_inOut;
char d_status;
};
#endif
//Filename: MarchingDirection.C
#include "MarchingDirection.h"
MarchingDirection::MarchingDirection(double FValue)
: d_F(FValue),
d_inOut(static_cast<int>(FValue)),
d_status('d'){}
//Filename: Grid2D.h
#ifndef included_GridPt
#define included_GridPt
#include "MarchingDirection.h"
#include <cstddef>
struct GridPt
{
GridPt();
double d_x, d_y;
MarchingDirection Fp1(double F=1.0), Fm1(double F=-1.0);
double d_lstDistFn;
};
#endif
//Filename: GridPt.C
#include "GridPt.h"
GridPt::GridPt()
: d_lstDistFn(0.0){}
You declared Fp1, Fm1 functions inside GridPt struct, they are not members
You could change to:
struct GridPt
{
GridPt();
double d_x, d_y;
MarchingDirection Fp1, Fm1;
double d_lstDistFn;
};
Initialize all your struct members shown as below:
GridPt::GridPt()
: d_x(0.0),
d_y(0.0),
Fp1(1.0),
Fm1(-1.0),
d_lstDistFn(0.0)
{}