Call static member function by pointer - c++

I'm working on a small custom Assembler
I have a vector of struc to storing OPCODE informations (Mnemonic, number and type of argument, parsing function,...)
typedef char args_type_t;
typedef struct op_s {
std::string opcode;
char nbr_args;
args_type_t type[4];
int code;
Tryte (*fct)(std::vector<std::string>);
} op_t;
the parsing function is pointer on a static member function :
{"MOV", 2, {T_REGISTER | T_ADDRESS, T_REGISTER | T_ADDRESS | T_CONSTANT}, 1, &Opcodes::MOV},
and the function :
class Opcodes
{
public:
static Tryte Opcodes::MOV(std::vector<std::string> _opMap) {
return Tryte(0);
}
};
I try this, but I get SEGFAULT (str() is a member function of Tryte) :
for (int i = 0; i < opMap.size(); i++) {
for (int j = 0; j < op_tab.size(); j++) {
if (!op_tab[j].opcode.compare(opMap[i][2])) {
std::cout << "OPBYTE : " << op_tab[j].fct(opMap[i]).str() << std::endl;
}
}
}
I want to call my function without instanciate Opcodes object it's posible ?
EDIT :
my error was here : if (!op_tab[j].opcode.compare(opMap[i][2]))
my mnemonic is the 1st item n opMap

Your code seems right, so perhaps a debugger information could help a bit.
But we can try to improve the friendlyness of the code by using a std::function:
typedef char args_type_t;
#include <functional>
typedef struct op_s {
std::string opcode;
char nbr_args;
args_type_t type[4];
int code;
std::function<Tryte(std::vector<std::string>>)> fct;
} op_t;
As for the sefgault, send us the backtrace.
Also, try to use range-based-for as it doesn't needs to tranverse the map to get the element again (as you are doing inside of the inner loop)
for (auto op : opMap) {
for (auto tab : op_tab) {
if (!tab.opcode.compare(op[1])) {
std::cout << "OPBYTE : " << tab.fct(op).str() << std::endl;
}
}
}
One common fix that you can do to not miss the indexes anymore is to use an Enum holding the possibilities.
enum Columns {
FuncPointer,
UserData
}
for (auto op : opMap) {
for (auto tab : op_tab) {
if (!tab.opcode.compare(op[FuncPointer])) {
std::cout << "OPBYTE : " << tab.fct(op).str() << std::endl;
}
}
}

Related

Iterate over struct pointer

Given a struct pointer to the function. How can I iterate over the elements and do not get a segfault? I am now getting a segfault after printing 2 of my elements. Thanks in advance
#include <stdio.h>
#include <string>
#include <iostream>
using namespace std;
struct something{
int a;
string b;
};
void printSomething(something* xd){
while(xd){
cout<<xd->a<<" "<<xd->b<<endl;
xd++;
}
}
int main()
{
something m[2];
m[0].a = 3;
m[0].b = "xdxd";
m[1].a = 5;
m[1].b = "abcc";
printSomething(m);
return 0;
}
You'll have to pass the length of the array of struct
void printSomething(something* xd, size_t n){
//^^^^^^^^ new argument printSomething(m, 2);
size_t i = 0;
while(i < n){ // while(xd) cannot check the validity of the xd pointer
cout<<xd->a<<" "<<xd->b<<endl;
xd++;
i++;
}
}
You should better use std::vector<something> in C++
The problem is that you are assuming there is a nullptr value at the end of the array but this is not the case.
You define a something m[2], then
you take the address of the first element, pointing to m[0]
you increase it once and you obtain address to m[1], which is valid
you increase it again, adding sizeof(something) to the pointer and now you point somewhere outside the array, which leads to undefined behavior
The easiest solution is to use a data structure already ready for this, eg std::vector<something>:
std::vector<something> m;
m.emplace_back(3, "xdxd");
m.emplace_back(5, "foo");
for (const auto& element : m)
...
When you pass a pointer to the function, the function doesn't know where the array stops. After the array has decayed into a pointer to the first element in the array, the size information is lost. xd++; will eventually run out of bounds and reading out of bounds makes your program have undefined behavior.
You could take the array by reference instead:
template <size_t N>
void printSomething(const something (&xd)[N]) {
for (auto& s : xd) {
std::cout << s.a << " " << s.b << '\n';
}
}
Now xd is not a something* but a const reference to m in main and N is deduced to be 2.
If you only want to accept arrays of a certain size, you can make it like that too:
constexpr size_t number_of_somethings = 2;
void printSomething(const something (&xd)[number_of_somethings]) {
for (auto& s : xd) {
std::cout << s.a << " " << s.b << '\n';
}
}
int main() {
something m[number_of_somethings];
// ...
printSomething(m);
}
Another alternative is to pass the size information to the function:
void printSomething(const something* xd, size_t elems) {
for(size_t i = 0; i < elems; ++i) {
std::cout << xd[i].a << " " << xd[i].b << '\n';
}
}
and call it like this instead:
printSomething(m, std::size(m));
Note: I made all versions const something since you are not supposed to change the element in the `printSomething´ function.

Class design - use optionals? variants? be opaque?

I want to have a class for PCI bus locations. For the sake of discussion, these come in three forms:
[domain]:[bus]:[device].[function]
[domain]:[bus]:[device]
[bus]:[device].[function]
and let's say each field is a non-negative integral value (let's even say unsigned just to make things simple).
I'm scratching my head regarding how to define this class. I could use std::optionals for the domain and function fields; but then, they're not both optional. I could use a variant with 3 types, but then I need to define separate types, which overlap a lot. I could just hold 4 unsigneds and a 3-value enum for which format is in effect - but that's quite a bit of hassle, and I'd need getter and to make the class opaque. Same thing if I try to use a union somehow.
It seems like every choice I make, it's going to be an iffy class. How can I minimize my displeasure with it?
Note: Any language standard version is ok for the answer, although I doubt C++20 would give you anything.
Building upon my comment, I was wondering if something like this could work:
enum class pci_format { domain_function, domain, function };
template <pci_format E> struct tag { };
class pci_location {
public:
pci_location (tag<pci_format::domain_function>, unsigned domain, unsigned bus,
unsigned device, unsigned function)
: format_(pci_format::domain_function)
, domain_(domain)
, bus_(bus)
, device_(device)
, function_(function)
{ }
// Repeat for other values of pci_format.
pci_format format () const { return format_; }
bool has_domain () const {
return (format_ == pci_format::domain_function)
or (format_ == pci_format::domain);
}
unsigned domain () const {
if (not has_domain()) { throw std::runtime_error("Domain not available."); }
return domain_;
}
// Repeat for other fields.
private:
pci_format format_;
unsigned domain_;
unsigned bus_;
unsigned device_;
unsigned function_
};
You would basically create a specific constructor for each PCI "format". Of course you could also store each unsigned as an std::optional<unsigned>, but that would force users to "dereference" each optional even if they knew for sure that it must contain a value.
One way or another, they'll have to check what "format" the location is in, so it seems to me that using an enum for this is more user friendly. Then users only have to check once and know exactly which fields are available.
I guess you could layer a visitor on top of all this so they can simply provide code to execute for each "format":
struct pci_location_visitor {
virtual void visit (tag<pci_format::domain_function>, pci_location const & obj) = 0;
// Repeat for other enum values.
};
// Add to pci_location:
void accept (pci_location_visitor & visitor) {
switch (format_) {
case pci_format::domain_function:
return visitor.visit(tag<pci_format::domain_function>{}, *this);
default: throw std::runtime_error("Format not supported for visitation.");
}
}
Then on top of that you could create a visitor that can be constructed from a bunch of callables, i.e. lambdas, so that this all can be used like below:
pci_location const & loc = getIt();
auto printSomething = make_pci_location_visitor(
[](tag<pci_format::domain_function>, pci_location const & e) { std::cout << e.domain(); }
, [](tag<pci_format::domain>, pci_location const & e) { std::cout << e.bus(); }
, [](tag<pci_format::function>, pci_location const & e) { std::cout << e.function(); }
);
loc.accept(printSomething);
For an example of how such a visitor could be constructed, see the overloaded class in the std::visit example on cppreference.com.
As requested in comments... given that I have no particular requirements how the users would prefer to use this class, given C++14, I would be doing something generic along the lines of:
#include <array>
#include <climits>
#include <iostream>
#include <stdexcept>
class pci_location_t {
public:
struct dbdf {
unsigned int domain;
unsigned int bus;
unsigned int device;
unsigned int function;
};
struct dbd {
unsigned int domain;
unsigned int bus;
unsigned int device;
};
struct bdf {
unsigned int bus;
unsigned int device;
unsigned int function;
};
pci_location_t(dbdf v) : domain(v.domain), bus(v.bus), device(v.device), function(v.function) {}
pci_location_t(dbd v) : domain(v.domain), bus(v.bus), device(v.device), function(INVALID) {}
pci_location_t(bdf v) : domain(INVALID), bus(v.bus), device(v.device), function(v.function) {}
template <typename dbdf_f, typename dbd_f, typename bdf_f>
auto visit(dbdf_f dbdf_fun, dbd_f dbd_fun, bdf_f bdf_fun) const {
if (domain == INVALID) {
if (function == INVALID) {
throw std::domain_error("Wrong PCI location format");
}
return bdf_fun(bdf{bus, device, function});
} else if (function == INVALID) {
return dbd_fun(dbd{domain, bus, device});
} else {
return dbdf_fun(dbdf{domain, bus, device, function});
}
}
private:
friend pci_location_t invalid_location();
pci_location_t() : domain(INVALID), bus(INVALID), device(INVALID), function(INVALID) {}
const static unsigned int INVALID = UINT_MAX;
unsigned int domain;
unsigned int bus;
unsigned int device;
unsigned int function;
};
pci_location_t invalid_location() { return pci_location_t{}; }
int main() {
std::array<pci_location_t, 4> locations = {
pci_location_t(pci_location_t::dbdf{1, 2, 3, 4}),
pci_location_t(pci_location_t::dbd{1, 2, 3}),
pci_location_t(pci_location_t::bdf{2, 3, 4}),
invalid_location()
};
try {
for (auto& l : locations) {
l.visit(
[] (auto dbdf) {
std::cout << dbdf.domain << ":" << dbdf.bus << ":" << dbdf.device << "." << dbdf.function << std::endl;
},
[] (auto dbd) {
std::cout << dbd.domain << ":" << dbd.bus << ":" << dbd.device << std::endl;
},
[] (auto bdf) {
std::cout << bdf.bus << ":" << bdf.device << "." << bdf.function << std::endl;
}
);
}
std::cout << "Done!" << std::endl;
} catch(const std::exception& e) {
std::cout << e.what() << std::endl;
}
return 0;
}
(you can check it on Coliru).
Feel free to use optionals or a separate format field if you don't like special values.
I'd make both the domain and the function optional (I don't really care how, as long as it's effective), and just enforce the only-one-missing condition as a class invariant. That is, only the functions that can change any of the fields need to perform the check and signal possible errors back to the user. No need to bloat your code with variants, or with dynamically interpreted unsigned int arrays. KISS.

C++ Segmentation fault while dereferencing a void pointer to a vector

#include <iostream>
#include <vector>
#include <mutex>
struct STRU_Msg
{
std::string name;
void *vpData;
};
class CMSG
{
public:
template <typename T>
int miRegister(std::string name)
{
STRU_Msg msg;
msg.name = name;
msg.vpData = malloc(sizeof(T));
msgtable.push_back(msg);
std::cout << "registeratio ok\n";
return 0;
}
template <typename T>
int miPublish(std::string name, T tData)
{
for (int i = 0; i < msgtable.size(); i++)
{
if (!name.compare(msgtable[i].name))
{
(*(T *)msgtable[i].vpData) = tData;
std::cout << "SUccess!\n";
return 0;
}
else
{
std::cout << "cannot find\n";
return 0;
}
}
}
private:
std::vector<STRU_Msg> msgtable;
};
int main()
{
CMSG message;
std::string fancyname = "xxx";
std::vector<float> v;
// message.miRegister< std::vector<float> >(fancyname);
// for (int i = 0; i < 1000; i++)
// {
// v.push_back(i);
// }
// std::cout << "v[0]: " << v[0] << ", v[-1]: " << v[v.size()-1] << '\n';
// message.miPublish< std::vector<float> >(fancyname, v);
for (int i = 0; i < 1000; i++)
{
v.push_back(i);
}
std::cout << "v[0]: " << v[0] << ", v[-1]: " << v[v.size()-1] << '\n';
message.miRegister< std::vector<float> >(fancyname);
message.miPublish< std::vector<float> >(fancyname, v);
return 0;
}
What I want to achieve is to write a simple publish/subscribe (like ROS) system, I use void pointer so that it works for all data type. This is the simplified code.
If I publish an int, it works fine, but what really confuse me are:
If I pass a long vector (like this code), it gave me the
"segmentation fault (core dump)" error.
If I define the vector between "register" and "publish" (i.e. like
the commented part), this error goes away.
If I use a shorter vector, like size of 10, no matter where I define
it, my code run smoothly.
I use g++ in Linux.
Please help me fix my code and explain why above behaviors will happen, thanks in ahead!
You cannot copy std::vector or any other non-trivial type like that. Before you do anything (even assignment-to) with such an object, you need to construct it using a constructor and placement new.
A way to do this would be
new(msgtable[i].vpData) T;
Do this in the register function.
Then you can assign a value as you do.
Still better, do not use malloc at all, allocate your object with (normal, non-placement) new.
I however strongly suggest ditching void* and moving to a template based implementation of STRU_Msg. If you don't feel like reinventing the wheel, just use std::any.

How to initialize items in a range in a captureless lambda, C++

My code is below. This works, It allows me to have exactly one range in my lambda.
So I guess what my question is, is how do I achieve the same results without using
"if(LOOP > 2 && LOOP < 5){int THERANGEVALUE = 2; FUNC[THERANGEVALUE]();}"?
And instead initialize an item in my captureless lambda as being ranged instead. aka, item_2 being item_range(2,4). And then also being able to continue my lambda normally, whereas Item_3 will equate to item_5.
Thank you for any help in advance, I will gladly add more input if requested.
#include <iostream>
using namespace std;
void (*FUNC[3])(void) = { //captureless lambda.
/*ITEM_0*/[](){ cout << "x" << endl;},
/*ITEM_1*/[](){cout << "y" << endl;},
/*ITEM_2->ITEM_4*/[](){cout<<"z";}
};
/*Here the [](){code;} lambda is acting as a stand-in for void FUNC() so it shouldn't touch anything outside of its scope*/
int LOOP = 4;
int main()
{
if(LOOP > 2 && LOOP < 5){int THERANGEVALUE = 2; FUNC[THERANGEVALUE]();}
FUNC[LOOP]();
return 0;
}
Adding on to this, below is the solution I came up with after asking a friend. To my surprise it was actually a lot simpler than I expected. While I couldn't initialize each item in the lambda in a range easily, I could pass it into an array and set a range inside of the array instead. So while it's not quite what I was looking for, it's...good enough for my purposes. Thanks Jaime if you see this. Otherwise I'd use PilouPili's answer below.
#include <iostream>
using namespace std;
void (*FUNC[4])(void) = { //captureless lambda.
/*ITEM_0*/ [](){ cout << "x" << endl;},
/*ITEM_1*/ [](){cout << "y" << endl;},
/*ITEM_2->ITEM_4*/[](){cout<<"z";},
/*ITEM_5*/ [](){cout<<"z";}
};
int LOOP = 4;
int main()
{
int ARR[5]={};
for(int I = 0; I < 6;I=I+1){//handling of ranged values.
if(I>2 && I<5){ARR[I]=2;} else {ARR[I]=I;}
}
FUNC[ARR[LOOP]]();
return 0;
}
I only see to way :
either extend your function array -> That's FUNC1 in the next example
change the value given in operator [] -> That's FUNC2 in the next example
#include <iostream>
#include <vector>
using namespace std;
std::vector<void (*)(void)> init_FUNC()
{
std::vector<void (*)(void)> func(5, [](){cout<<"z";});
func[0]=[](){ cout << "x" << endl;};
func[1]=[](){ cout << "y" << endl;};
return func;
}
std::vector<void (*)(void)> FUNC1= init_FUNC();
class FUNC_MAP
{
void (*_FUNC[3])(void) = { //captureless lambda.
/*ITEM_0*/[](){ cout << "x" << endl;},
/*ITEM_1*/[](){cout << "y" << endl;},
/*ITEM_2->ITEM_4*/[](){cout<<"z";}
};
typedef void (*FUNC_MAP_OUT)(void);
public:
FUNC_MAP_OUT operator[](int i)
{
if(i>2 && i<5)
{return _FUNC[2];}
else
{return _FUNC[i];}
}
};
FUNC_MAP FUNC2;
/*Here the [](){code;} lambda is acting as a stand-in for void FUNC() so it shouldn't touch anything outside of its scope*/
int LOOP = 1;
int main()
{
FUNC1[LOOP]();
FUNC2[LOOP]();
return 0;
}

Getting an error when i call a structure variable by using pointer with array subscription

// Menu Structure
struct Menu
{
char* name;
void (*func) ();
};
Menu* tmpPtr = NULL;
// Menu Function prototypes
void fileFunction();
void editFunction();
void viewFunction();
void exitFunction();
int main(int argc, char *argv[])
{
unsigned selection = 0 ;
Menu menuStruct[] = {
{"file", fileFunction},
{"edit", editFunction},
{"view", viewFunction},
{"exit", exitFunction} };
tmpPtr = menuStruct;
while(selection != 4)
{
for(int i = 0 ; i < 4 ; i++)
{
std::cout << i+1 <<" : " << tmpPtr->name << std::endl;
tmpPtr++;
}
tmpPtr = menuStruct;
std::cout<< "Enter Selection Value: " ;
std::cin>>selection;
if(selection <= 4)
*(tmpPtr[selection-1]->func)();
}
return 0;
}
Error received: base operand of '->' has non pointer type Menu
But it is working when i use (**(tmpPtr+selection-1)->func)(); as far as my knowledge both are same,
I donno why this error is coming, please help me to figure out the mistake am doing?
The line
*(tmpPtr[selection-1]->func)();
is a problem since the type of tmpPtr[selection-1] is Menu, not Menu*. You need to use:
*(tmpPtr[selection-1].func)();
Update
Due to operator precedence, the line
*(tmpPtr[selection-1].func)();
is the same as
*((tmpPtr[selection-1].func)());
Since the return type of Menu:func is void, that line is equivalent to:
*(void)
which is not right.
You can use:
(*tmpPtr[selection-1].func)();
or, simply:
tmpPtr[selection-1].func();