I'm writing a C++ Class with provides a pool of buffers. The class contains the actual (private) pool and a public function with return a pointer to a free buffer. The class declaration is within a hpp file.
CTransmissionBuffers.hpp
class CTransmissionBuffers {
public:
static constexpr uint32_t buffer_length = 1000;
struct Transmissionbuffer_T
{
osMutexId mutex;
uint8_t data[buffer_length];
osThreadId thread_id;
};
CTransmissionBuffers();
virtual ~CTransmissionBuffers();
static bool Init_Transmission_Buffers();
static Transmissionbuffer_T* Get_New_Transmission_Buffer();
static void Free_Transmission_Buffer(Transmissionbuffer_T* pBuffer);
private:
static constexpr uint32_t n_buffer = 3;
static Transmissionbuffer_T buffer_pool[n_buffer];
};
CTransmissionBuffers.cpp
#include <CTransmissionBuffers.hpp>
CTransmissionBuffers::Transmissionbuffer_T buffer_pool[CTransmissionBuffers::n_buffer] = {}; /// this causes the problem
CTransmissionBuffers::CTransmissionBuffers()
{
// TODO Auto-generated constructor stub
}
CTransmissionBuffers::~CTransmissionBuffers()
{
// TODO Auto-generated destructor stub
}
bool CTransmissionBuffers::Init_Transmission_Buffers()
{
for (uint32_t i = 0; i < n_buffer; i++)
{
buffer_pool[i].mutex = osMutexCreate(nullptr);
if (nullptr == buffer_pool[i].mutex)
{
return false;
}
}
return true;
}
CTransmissionBuffers::Transmissionbuffer_T* CTransmissionBuffers::Get_New_Transmission_Buffer()
{
Transmissionbuffer_T* pBuffer = nullptr;
for (uint32_t i = 0; i < n_buffer; i++)
{
if (osOK == osMutexWait(buffer_pool[i].mutex, 0))
{
//Mutex erhalten
pBuffer = &(buffer_pool[i]);
break;
}
}
return pBuffer;
}
void CTransmissionBuffers::Free_Transmission_Buffer(Transmissionbuffer_T* pBuffer)
{
if(nullptr == pBuffer)
{
return;
}
osMutexRelease(pBuffer->mutex);
}
After compiling this I got a undefined reference to buffer_pool, so I tried to add a
CTransmissionBuffers::Transmissionbuffer_T buffer_pool[CTransmissionBuffers::n_buffer] = {};
to the corresponding cpp file but a can't access n_buffer because it's private :(
Do I have to define a static member? Do you have some good ideas how to solve this problem?
Greets Julian
Your syntax is off. Transmissionbuffer_T is not a member of your class, but is the type of a member of your class. A static definition should look like this:
Transmissionbuffer_T CTransmissionBuffers::buffer_pool[CTransmissionBuffers::n_buffer]={};
In C++17 you can use an inline variable as a more convenient way to work around this issue:
class CTransmissionBuffers {
//...
private:
//...
inline static Transmissionbuffer_T buffer_pool[n_buffer];
}
If you declare it an inline variable, do not also declare the variable in the outside the class or you'll have duplicate definitions and get an error.
Note: constexpr static members are implicitly inline, so don't need to do anything for n_buffer to work correctly.
after doing some reasearch it turns out that inline variables are only supported with gcc 7
(see https://gcc.gnu.org/projects/cxx-status.html)
I'm stuck with gcc6 however.
I initialised the buffers by placing a
CTransmissionBuffers::Transmissionbuffer_T CTransmissionBuffers::buffer_pool[n_buffer] = {};
at the beginning of the cpp file. That seams to work. Thanks alot for your help :)
Related
I intend to use a library with a declaration of a variable in one of its function
/// in library A
function fun(){
static int iwanttouse = 1;
/// operation on iwanttouse
}
How can i use it in Application B? Do I connect it with extern
extern int iwanttouse;
// and then use it
if(iwanttouse == x)
.....
or I could use them without declaration?
No. Static variables have internal linkage, precisely so that you can't do that.
Don't use global variables, they make unit testing of your code next to impossible, use dependency injection instead.
Example:
#include <iostream>
// header file.
// Define a struct with all the data you need globally
struct my_data_t
{
bool i_want_house = true;
};
// Get a static instance
my_data_t& getGlobalData()
{
static my_data_t data;
return data;
};
// Put code where you want to use data in a class.
class my_class_t
{
public:
// constructor with dependency injection!
// this way any data can be injected (valuable for unit testing!)
explicit my_class_t(my_data_t& data) :
m_data{ data }
{
}
void show_i_want_house()
{
// use data
if (m_data.i_want_house)
{
std::cout << "I really want that house!\n";
}
else
{
std::cout << "Nah, this house is not good enough\n";
}
}
private:
my_data_t& m_data;
};
// cpp file
int main()
{
// instantiate objects with a reference to the data you want it to use.
my_class_t object_with_global_data{ getGlobalData() };
object_with_global_data.show_i_want_house();
my_data_t test_data{ false }; //aggregate initialization of struct
my_class_t object_with_test_data{ test_data }; //create an object with non-global data for testing
object_with_test_data.show_i_want_house();
return 0;
}
A variable marked with the keyword static(outside the class) is only visible to that translation unit. static elements are allocated storage only once in a program lifetime in static storage area. And they have a scope till the program lifetime.
So in your case, static int iwanttouse = 1; is not even seen by another translation unit. :)
I'm debugging a program (segfault) using LLDB on MacOS Big Sur. I have these types:
class Pkt {
public:
std::uint8_t header;
Pkt(std::uint8_t header): header(header) {
}
};
class Pkt1 : public Pkt {
public:
static inline const std::uint8_t headerVal = 0x01;
static inline bool matchHeader(std::uint8_t byte) {
return (byte == headerVal);
}
Pkt1(std::uint8_t header): Pkt(header) {}
};
class Pkt2 : public Pkt {
public:
static inline const std::uint8_t headerVal = 0x02;
static inline bool matchHeader(std::uint8_t byte) {
return (byte == headerVal);
}
uint32_t pkt2Var;
Pkt2(std::uint8_t header): Pkt(header) { pkt2Var = 33; }
};
class PktGen {
private:
public:
std::queue<std::shared_ptr<Pkt>> pkts;
void genPkt(uint8_t header) {
if(Pkt1::matchHeader(header)) {
pkts.push(std::make_shared<Pkt1>(header));
}
if(Pkt2::matchHeader(header)) {
pkts.push(std::make_shared<Pkt2>(header));
}
}
std::queue<std::shared_ptr<Pkt>> getPkts() {
std::queue<std::shared_ptr<Pkt>> tmp;
tmp = pkts;
while(!pkts.empty()) {
pkts.pop();
}
return tmp;
}
};
There's probably something wrong with my getPkts() function, though it works here: https://godbolt.org/z/h8Y4qPKnh.
Anyway, my question is with LLDB: if I want to access:
p std::static_pointer_cast<std::shared_ptr<Pkt1>>(pkts.front())->pkt2Var
I get:
error: <user expression 42>:1:6: no template named 'static_pointer_cast' in namespace 'std'
How do I go about casting smart pointers in LLDB?
std::static_pointer_cast requires #include <memory>.
But in any case, your use of std::static_pointer_cast is just plain wrong anyway.
DON'T specify shared_ptr itself in the template parameter, only the pointer type being casted to, eg:
p std::static_pointer_cast<Pkt1>(pkts.front())->pkt2Var
However, Pkt1 does not have any pkt2Var member, but Pkt2 does:
p std::static_pointer_cast<Pkt2>(pkts.front())->pkt2Var
If the debugger still won't accept static_pointer_cast, then just use an ordinary static_cast instead (since you don't need the debugger taking shared ownership anyway):
p static_cast<Pkt2*>(pkts.front().get())->pkt2Var
I am trying to create a dynamic function pointer that points to some methods all the methods I want to save on the array return a bool and have an uint32_t parameter. The functions are Service functions. These are intended to be dynamic, so when a class is started, the constructor links the service function from the object to be called from outside the object.
With the code below I am getting the following error:
Build error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.
I have no clue what to do to overcome this problem, any idea would be greatly appreciated, thanks!
//File 1
typedef bool (*ServiceFunctionsType)(uint32_t);
//File 2
#include "File1.hpp"
extern uint8_t ServiceFunctions_size;
extern ServiceFunctionsType *ServiceFunctions;
void Service_Functions_Setup();
bool SetPtr(ServiceFunctionsType a);
void ClearPtr(uint8_t id);
//File 3
#include "File1.hpp"
ServiceFunctionsType *ServiceFunctions;
uint8_t ServiceFunctions_size = 0;
//File 4
#include "File2.hpp"
#include <stdlib.h>
void Service_Functions_Setup()
{
ServiceFunctions = NULL;
if(SERVICE_FUNCTION_POINTER_START_SIZE != 0)
{
ServiceFunctions_size = SERVICE_FUNCTION_POINTER_START_SIZE;
ServiceFunctions = (ServiceFunctionsType*)malloc(sizeof(ServiceFunctionsType)*SERVICE_FUNCTION_POINTER_START_SIZE);
for(uint8_t i = 0; i < SERVICE_FUNCTION_POINTER_START_SIZE; i++)
{
ServiceFunctions[i] = NULL;
}
}
}
uint8_t SetServiceFunctionPointer(ServiceFunctionsType a, bool _realloc)
{
if( ServiceFunctions == NULL )
{
ServiceFunctions = (ServiceFunctionsType*)malloc(sizeof(ServiceFunctionsType));
ServiceFunctions[0] = a;
return 0;
}
for(uint8_t i = 0; i < ServiceFunctions_size; i++)
{
if( ServiceFunctions[i] == NULL )
{
ServiceFunctions[i] = a;
return i;
}
}
if(_realloc)
{
ServiceFunctions_size++;
ServiceFunctions = (ServiceFunctionsType*)realloc(ServiceFunctions,sizeof(ServiceFunctionsType)*ServiceFunctions_size);
ServiceFunctions[ServiceFunctions_size - 1] = a;
return ServiceFunctions_size - 1;
}
return INVALID_SERVICE_FUNCTION_POINTER;
}
void ClearServiceFunctionPointer(uint8_t id)
{
ServiceFunctions[id] = NULL;
}
//File 5
class MonoStepSequencer
{
public:
MonoStepSequencer();
~MonoStepSequencer();
uint8_t ServicePointerID;
bool Service(uint32_t time);
private:
};
//File 6
#include "File2.hpp"
MonoStepSequencer::MonoStepSequencer()
{
ServicePointerID = SetServiceFunctionPointer(&this -> Service);
}
//This is the function to be called with a pointer
bool MonoStepSequencer::Service(uint32_t time)
{
//Some Code
}
You can try, to use lambdas. Create method like
std::function<void()> getService()
Where inside you can use:
return [this](){
Service();
};
Also if your methods should use arguments, you can use this method, but add arguments into return value and lambda.
One more, you can create lambda outside of class methods, like:
[&object]()
{
object.Service();
}
In this way, better to use std::shared_ptr to guŠ°rantee that object exists, when lambda called.
this -> Service is an unqualified or parenthesized non-static member function
You probably meant :: instead of -> Also, you need a type on the left, not a variable.
Also, please don't put spaces around ->. That makes it look like you're specifying a trailing return type or something.
i was wondering if is possible make that a method of class points to another method of other class:
consider this:
// Class Foo:
class Foo
{
static int GetA(int a);
static int GetB(int b);
};
int Foo::GetA(int a)
{
return a * 2;
}
int Foo::GetB(int b)
{
return a * 4;
}
// Hooking class methods:
class HookFoo
{
static int HookGetA(int);
static int HookGetB(int);
};
int(HookFoo::*HookGetA)(int) = (int(HookFoo::*)(int))0x0; // (0x0 Memory address) or for example: &Foo::GetA;
int(HookFoo::*HookGetB)(int) = (int(HookFoo::*)(int))0x0; // (0x0 Memory address) or for example: &Foo::GetA;
I know it's possible do some like:
int(*NewHook)(int) = &Foo::GetA;
but how i can do for declare the methods into of a class?
Here is more or less what you tried to achieve (minimal, working example):
class Foo
{
public:
static int GetA(int a);
static int GetB(int b);
};
int Foo::GetA(int a)
{
return a * 2;
}
int Foo::GetB(int b)
{
return b * 4;
}
class HookFoo
{
public:
using FuncType = int(*)(int);
static FuncType HookGetA;
static FuncType HookGetB;
};
// Initialized with Foo::GetA
HookFoo::FuncType HookFoo::HookGetA = &Foo::GetA;
// nullptr'ed
HookFoo::FuncType HookFoo::HookGetB = nullptr;
int main() {
HookFoo::HookGetA(0);
}
For the methods in Foo are static, you can use a simple function pointer type to refer to them. You don't have to use (and can't use actually) a member function pointer in this case.
The using declaration helps to have a more readable code.
When you have correctly initialized your hooks, you can invoke them (thus the pointed functions) as you can see in the main.
I added a couple of visibility specifiers for your methods and data members were all private.
You can use function pointers.
Ex:
class A {
public:
static void say_hello() { cout << "Hello\n"; }
};
class B {
public:
static void(*hook)();
};
void(*B::hook)() = A::say_hello;
int main()
{
B::hook();
}
If you need to hook into functions at a specific address, use a function pointer. You can't reassign functions like that
// typedef your function pointers, it makes the syntax a lot easier
typedef int(*FHook)(int);
class HookFoo
{
static FHook HookGetA;
static FHook HookGetB;
};
// assign to address
FHook HookFoo::HookGetA = (FHook)0x1234;
FHook HookFoo::HookGetB = (FHook)0x5678;
Of course its your job to make sure the addresses are correct.
the explicit function pointer types would be as such:
class HookFoo
{
static int (*HookGetA)(int);
static int (*HookGetB)(int);
};
int (*HookFoo::HookGetA)(int) = (int(*)(int))0x1234;
int (*HookFoo::HookGetB)(int) = (int(*)(int))0x5678;
I defined a class in the header file like this:
class myClass
{
public:
void test();
void train();
private:
bool check;
}
Then in the cpp file, I did this:
void myClass::test()
{
int count = 9;
//some other work
}
void myClass::train()
{
int newValue = count;
....
}
Then without surprise, I got an error saying count is not defined. So what I want to do is in my train function use the count value that is defined in the test. Is there any good way to do this without using any additional dependencies? Thank you.
Well yes. That's called a member variable. Exactly like your bool check;.
Do
private:
bool check;
int count;
and then use it directly in your functions.
void myClass::test()
{
count = 9;
//Same as this->count = 9;
}
void myClass::train()
{
int newValue = count;
//Same as int newValue = this->count;
}
In your example, when method test finishes its work, count variable does not exist anymore, so there's no way of accessing it. You have to ensure, that its lifetime will be long enough to be accessed from another place. Making it a class field solves the problem (this is what class fields are for :)).
Do it this way:
class myClass
{
public:
void test();
void train();
private:
bool check;
int count; // <- here
}
and then
void myClass::test()
{
count = 9;
//some other work
}
But that's not the only solution. You can do it in another way, say:
class myClass
{
public:
int test()
{
// do some work
return 9;
}
void train(int count)
{
int newValue = count;
}
}
// (somewhere)
myClass c;
int count = c.test();
c.train(count);
That all depends on what test, train and count are for...