Simple reflection mechanism - c++

Is there any solution to run a function/macro that name is created by concatenation of two strings?
I just want to do something like that:
template <char *A, char *B, int C>
int function_that_run_other_function(void){
// Here is the main point
char function_name[80];
strcpy (function_name, "function");
strcat (function_name, A);
strcat (function_name, B);
return function_name(C);
}
I can do this using macro:
#define macro_that_run_function(A,B,C) \
function_##A##B##(C);
But I don't want to use macro because of many problems with macros.
Is it possible to do in C++ without any additional libraries?

I got curious and after a little while I ended up with this ungodly mess and general mainentace nightmare:
main.cpp:
#include <map>
#include <iostream>
#include <sstream>
#include <functional>
#include <cstring>
typedef std::function<void(int)> func;
typedef std::map<std::string, func> FuncMap;
template <char* A, char* B, int C>
void runner(FuncMap funcs){
std::stringstream ss;
ss <<A <<B;
return funcs[ss.str()](C);
}
void ABC(int val) {
std::cout <<"Woo: " <<val <<"\n";
}
extern char a[]; //due to external linkage requirement
extern char b[];
int main(...) {
FuncMap funcs;
strcpy(a, "A");
strcpy(b, "B");
funcs["AB"] = std::bind(&ABC, std::placeholders::_1);
runner<a, b, 0>(funcs);
return 0;
}
vars.cpp:
char a[5] = {""};
char b[5] = {""};
So yes with enough force you can make c++ do something along the lines of what you want, but I really wouldn't recommend it.

No, C++ does not allow the compile or run time manipulation or inspection of symbol names (barring the implementation specified type info stuff).
Dynamic libraries often export names (mangled for C++, almost unmangled for `extern "C"``), and libraries for loading them usually (always?) allow them to be loaded by string value.

Related

Extract the variable name of a pointer as a string

I have a pointer to an int object.
int x = 10;
int *ptr;
ptr = &x;
I want to write a function GetString(int *ptr) which would return me the string ptr. How do I do that in C++?
There isn't a direct way to extract a variable's string name in C++. The language has only rudimentary reflection features, see the type_traits standard library and SO post Why does C++ not have reflection?.
But you can use preprocessor stringification # to hack something similar: define
#define STRINGIFY(x) #x
then the preprocessor substitutes STRINGIFY(ptr) with the string "ptr".
Note: if you want to stringify the result of a macro expansion use two levels of macros.
#include <iostream>
#include <map>
const std::string& getString(int *ptr, const std::map<int*, std::string>& mp){
return mp.find(ptr)->second;
}
int main()
{
std::map<int* , std::string> mp;
int x = 10;
mp.insert({&x, "ptr1"});
int y = 9;
mp.insert({&y, "ptr2"});
std::cout << getString(&y, mp);
}
Demo

include a header file built in c++ using extern in c program

I have a class in C++ which I want to make a shared library from it and use in C or other languages. this is the class that I want to make a library from it:
getinfo.h
#ifndef GETINFO_H
#define GETINFO_H
#include "info.h"
char* getMaximumSpeedCpu();
char* getCoreNumbers();
#endif
getinfo.cpp:
#include <iostream>
#include "getinfo.h"
using namespace Morsa::Prd::SMC::SL;
char* getMaximumSpeedCpu()
{
info *inf = new info;
std::string str = inf->maximumSpeedCpu();
char* maxspeed = new char[str.length()+1];
strcpy(maxspeed, str.c_str());
free(inf);
return maxspeed;
}
char* getCoreNumbers()
{
info *inf = new info;
std::string corenum = inf->coreNumbers();
char* num = new char[corenum.length()+1];
strcpy(num, corenum.c_str());
free(inf);
return num;
}
and this is my wrapper class (smc.h):
#ifndef SMC_H
#define SMC_H
#include "getinfo.h"
#ifdef __cplusplus
extern "C"
{
#endif
//void smc_destroy(ctestsmc *a);
char* smc_getMaximumSpeedCpu();
char* smc_getCoreNumbers();
#ifdef __cplusplus
}
#endif
#endif // SMC_H
smc.cpp:
#include "smc.h"
char *smc_getMaximumSpeedCpu()
{
char* c = getMaximumSpeedCpu();
return c;
}
char *smc_getCoreNumbers()
{
char* c = getCoreNumbers();
return c;
}
I made a shared library from smc.cpp, now I want to use my library in for example a C code.
How am I supposed to do it without including any header file? Whenever I include header file of smc, my C code doesn't know libraries that I had used in getinfo.h, like fstream.EDIT:
info.h:
#ifndef INFO_H
#define INFO_H
#include <stdlib.h>
#include <cstring>
#include <sys/statvfs.h>
#include <libssh/libssh.h>
class info
{
private:
std::ifstream ifile;
std::ofstream ofile;
std::vector<std::string> lists;
std::string str;
ssh_session my_ssh_session ;
public:
info();
info(const void *ip, const char* pw, const void *hostName);
~info();
std::string maximumSpeedCpu();
std::string coreNumbers();
const void* _hostName;
const void* _ip;
const char* _password;
info.cpp:
#include "info.h"
info::info(const void *ip, const char* pw, const void *hostName)
{
int a;
_ip = ip;
_password = pw;
_hostName = hostName;
my_ssh_session = ssh_new();
}
info::info()
{
}
info::~info()
{
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
}
std::string info::maximumSpeedCpu()
{
//maximum speed of cpu
getSSHState();
std::string cpuSpeed;
cpuSpeed = exec_ssh_command(my_ssh_session, "dmesg | grep 'MHz processor' | awk '{print $5}'" );
return cpuSpeed;
}
std::string info::coreNumbers()
{
//number of processors
getSSHState();
std::string coresNumber;
coresNumber = exec_ssh_command(my_ssh_session, "cat /proc/cpuinfo | grep processor | wc -l");
return coresNumber;
}
Theory
You can only access functions written in C from the world of C. Whenever calling C++ code from C, you must go through a wrapper function, in your case smc_* functions.
Now, note that the declaration of the wrapper functions, which is in the wrapper's header file smc.h does not need to include getinfo.hpp. This is the key insight. The wrapper's header merely tells any C program that includes it, the type of arguments and return values of the smc_* functions. The header must stick to C.
For example, see the image below. The functions foo and bar are declared in the wrapper.h file which only includes other C headers. The wrapper.cpp file which actually implements the wrapper, and uses other stuff from the C++ world (like the STL, or other classes) includes the C++ headers it needs.
In your case, smc.cpp will include getinfo.hpp, not smc.h.
However, the definitions of these wrapper functions needs to know the types of the C++ functions it is wrapping. Therefore, smc.cpp will include getinfo.h. Further, because this file will be compiled by a C++ compiler, it will understand any references to C++ STL in included headers.
EDIT: Code example
Suppose I want to wrap the class cppworld.
cppworld.hpp:
class cppworld {
public:
cppworld();
int one();
};
cppworld.cpp:
#include <iostream>
#include "cppworld.hpp"
cppworld::cppworld() {}
int cppworld::one() {
return 1;
}
I write a wrapper with wrapper.h and wrapper.cpp.
wrapper.h:
#ifdef __cplusplus
extern "C"
{
#endif
int get_one();
#ifdef __cplusplus
}
#endif
wrapper.cpp:
#include "wrapper.h"
#include "cppworld.hpp"
int get_one() {
cppworld obj = cppworld();
return obj.one();
}
I can compile wrapper.cpp and cppworld.cpp into a shared library.
Then, to use the library from C, I create the C program below.
cworld.c
#include <stdio.h>
#include "wrapper.h"
int main() {
printf("Calling one() returns: %d\n", get_one());
}
Whenever I include header file of smc, my C code doesn't know libraries that I had used in getinfo.h, like fstream.
Yeah, you need to give C the declarations (not the definition) of the functions you need, and those declarations cannot use C++ features (directly).
For instance, you cannot give C things like references, templates or overloaded functions. You cannot directly use arbitrary class objects either, like an std::string, but you can pass them around as opaque pointers since for C they are just pointers.
Regardless of how you do it, you need C to see only what appear to be C functions on the surface.

How to wrap std::vector to use in pure C

In my project I would like to use C++ and STL containers but have a problem that I have to include hw vendor headers (and link vendor lib and use some vendor C sources that also include the vendor headers) written in ANSI C, that contain C++ reserved keywords, for example:
vendor.h:
// Vendor header (read only)
struct Vendor_Export_Struct {
unsigned char* data;
};
struct Vendor_Export_Struct export; // <<< compilation error under C++
union Vendor_Union {
struct Vendor_Export_Struct export; // <<< compilation error under C++
};
What included into C++ will cause errors during compile: expected unqualified id before ‘export’. So I'm forced to use pure C and thinking if it would be possible simply wrap STL vector to kind of C API like this (with C++ implementation behind):
cvect.h :
typedef void* Vect_Type;
typedef void** Vect_Iterator_Type;
typedef void* Vect_Data_Type;
Vect_Type Vect_New();
void Vect_PushBack(Vect_Type v, Vect_Data_Type d);
Vect_Iterator_Type Vect_Begin(Vect_Type v);
Vect_Iterator_Type Vect_End(Vect_Type v);
Vect_Iterator_Type Vect_Next(Vect_Type v, Vect_Iterator_Type it);
But problem is how to pass on the vector and iterator. I think I would be forced to use reinterpret_cast when casting from std::vector<> -> void* -> std::vector<> on the C++ code side and still thinking how to cast/pass std::vector<>::iterator.
c_vect.cpp :
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include "c_vect.h"
typedef std::vector<void*> Vect_Container_Type;
Vect_Type Vect_New()
{
return static_cast<Vect_Type>(new Vect_Container_Type);
}
void Vect_PushBack(Vect_Type v, Vect_Data_Type d)
{
Vect_Container_Type& vref = *reinterpret_cast<Vect_Container_Type*>(v);
vref.push_back(d);
}
Vect_Iterator_Type Vect_Begin(Vect_Type v)
{
Vect_Container_Type& vref = *reinterpret_cast<Vect_Container_Type*>(v);
return &*vref.begin();
}
Vect_Iterator_Type Vect_End(Vect_Type v)
{
Vect_Container_Type& vref = *reinterpret_cast<Vect_Container_Type*>(v);
return &*vref.end();
}
Vect_Iterator_Type Vect_Next(Vect_Type v, Vect_Iterator_Type it)
{
Vect_Container_Type& vref = *reinterpret_cast<Vect_Container_Type*>(v);
Vect_Container_Type::iterator it_ = static_cast<Vect_Container_Type::iterator>(it); //<<<< ugly and not portable
if (it_ != vref.end())
{
++it_;
return &*it_;
}
return NULL;
}
main.c :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "c_vect.h"
#include "vendor.h"
typedef struct S_Connection {
size_t id;
char* name;
union Vendor_Union u;
Vect_Type sessions; // Another vector
} T_Connection;
typedef T_Connection* T_ConnectionPtr;
static void* makeConn(size_t id, const char* name)
{
T_ConnectionPtr ptr = (T_ConnectionPtr)malloc(sizeof(T_Connection));
ptr->id = id;
ptr->name = (char*)malloc(strlen(name) + 1);
strcpy(ptr->name, name);
return ptr;
}
int main(int argc, char* argv[])
{
Vect_Type conns = Vect_New();
Vect_Iterator_Type it;
unsigned i;
for (i = 0; i < 10; ++i) {
char name[20];
sprintf(name, "conn_%03d", i);
Vect_PushBack(conns, makeConn(i + 1, name));
}
// Iterate vector and access stored data
for (it = Vect_Begin(conns);
it != Vect_End(conns);
it = Vect_Next(conns, it)) {
T_ConnectionPtr cd = (T_ConnectionPtr)*it;
}
return 0;
}
So I'm not sure if all this is a good idea, probably not from several reasons. I just would like to avoid another redundant C vector implementation, take profit from STL iterators. The final code should be portable. Has someone been solving a similar problem like this? Or do you have a better idea how to cope with this?
There are methods now to access the raw data array of the Vector:
value_type* data() noexcept;
const value_type* data() const noexcept;
These extensions were added in C++11 exactly for your case, to interface third party libraries that only take the raw data array. Pass the returned pointer to C as an array that is also a pointer in C. You will likely need add vector.size() as another parameter.
Do not manipulate the vector while using the returned pointer.
I am by no means an expert in this topic, but I've run into this problem before, and I've found that there are two options that seem to work:
You can write a vector library in C yourself. I've often found that this isn't really as hard as it may seem, and then you don't have code that is reliant upon the C++ STL, which won't be supported in a lot of the places one may want to use C, like in embedded systems, for example.
You will have to make a header in the following form:
#ifdef __cplusplus
extern "C" {
#endif
/* Define all your C wrapper functions here */
/* For example: */
void VectorWrapper_Add(struct VectorWrapper *vector_wrapper, const struct VectorWrapper_DataType *data_to_add);
#ifdef __cplusplus
}
#endif
And then in the implementation file, you can put something like this:
#include "my_c_wrapper.h"
#include <vector>
/* Do something similar for all your functions... */
void VectorWrapper_Add(struct VectorWrapper *vector_wrapper, const struct VectorWrapper_DataType *data_to_add)
{
/* Your implementation might look something like this for such a function: */
vector_wrapper->_stl_vector->push_back(*data_to_add);
}
Most the time, what I end up doing is just creating my own libraries to manage these sorts of data structures; but again, the choice is yours.
I hope my answer helps you.

Trying to print an escape character x number of times

So I want to do something like
printf("%s", '\t'*3);
Im just wondering if there is a way to print something like that without looping
printf("%s%s%s", "\t", "\t", "\t"); ? Just kidding. But since you have tagged this as C++, and since I don't know what higher-level problem you are trying to solve here, have you considered just using the appropriate std::string constructor?
std::string s(3, '\t');
You can even use it with printf if you really insist...
printf("%s", std::string(3, '\t').c_str());
But why not just use std::cout?
std::cout << std::string(3, '\t');
About the "without looping" part... both printf and std::string may have loops in their implementations, of course. But that should not bother you.
assuming that you ment runtime loops and are allowed to use boost, you could create the strings at compile time using templates:
#include <iostream>
#include <boost/mpl/char.hpp>
#include <boost/mpl/string.hpp>
using namespace boost;
template <unsigned int C, int R>
struct repchrn
{
typedef typename mpl::push_back<typename repchrn<C, R - 1>::string, mpl::char_<C>>::type string;
static const char* getString() { return mpl::c_str<string>::value; }
};
template <unsigned int C>
struct repchrn<C, 0>
{
typedef mpl::string<> string;
static const char* getString() { return mpl::c_str<string>::value; }
};
int main() {
printf("%s", repchrn<'a', 5>::getString());
/* or */ std::cout << std::endl;
std::cout << repchrn<'a', 5>::getString();
}

C++ preprocesor macro for accumulating comma-separated strings

I need to do the following:
const char* my_var = "Something";
REGISTER(my_var);
const char* my_var2 = "Selse";
REGISTER(my_var2);
...
concst char* all[] = { OUTPUT_REGISTERED }; // inserts: "my_var1, my_var2, ..."
REGISTER and OUTPUT_REGISTERED are preprocesor macros. This would be great for large number of strings, like ~100. Is it possible to accomplish this?
PS. The code belongs to level-0 "block" – i.e. it is not inside any function. AFAIK, I cannot call regular functions there.
#include <iostream>
#include <vector>
using namespace std;
vector<const char*>& all()
{
static vector<const char*> v;
return v;
}
struct string_register
{
string_register(const char* s)
{
all().push_back(s);
}
};
#define REGISTER3(x,y,sr) string_register sr ## y(x)
#define REGISTER2(x,y) REGISTER3(x,y,sr)
#define REGISTER(x) REGISTER2(x, __COUNTER__)
REGISTER("foo");
REGISTER("bar");
int main()
{
}