Using a config file to allocate array at compile time in c++ - c++

I am a bit new to c++ and want to learn more by trying a specific project. This project is somewhat bigger project where I want to test the dependence of some numerical method "function" with respect to parameters like array size and what not. I figured the best way to organize my code would be to create
A file implementing the functions I want to use
// implement.h
#include <cmath>
struct input_params{
int input_array_size;
// other parameters
}
void function(float* , float* , input_params);
// implement.cpp
#include <cmath>
#include "implement.h"
void function(float *input, float *output, input_params args){
// do stuff
}
A config file specifying what my input_params will contain (with a corresponding header file)
#include "config.h"
input_params args;
#include "implement.h"
#include "config.h"
input_params args;
args.input_array_size = 100; // something I would change before compile time
A script that will actually run the code
#include <cmath>
#include "implement.h"
#include "config.h"
// float *input = new [arg.input_array_size];
float input[arg.input_array_size]; // I want to make this stack-allocated for performance reasons
// float *output = new [arg.output_array_size];
float output[arg.output_array_size];
function(input, output, args);
My questions are as follows:
How should I compile the code using g++?
How do compile my "config" file so that my parameters are known at compile time?
Is there a better, alternative way of actually doing this?

The simplest approach would be to make your configuration file create macros:
// config.h
#define ARG_INPUT_SIZE 100
#define ARG_OUTPUT_SIZE 300
// some_other_file.c
#include "config.h"
float input[ARG_INPUT_SIZE];
float output[ARG_OUTPUT_SIZE];
It's pretty unlikely that allocating this in the bss vs the heap is actually going to be meaningfully important to any performance metrics.

"Is there a better, alternative way of actually doing this?"
Of course there is. Just use a std::vector<float> for the input / output parameters. You can adapt the necessary size of them dynamically as needed.
If you still want fixed sizes, and do that at compile time you can use std::array<float,MY_SIZE> and define the size you want using the -D command line option of g++:
g++ -D MY_SIZE=100 ...
std::vector and std::array are a lot easier to deal with than raw c-style arrays or pointers.
Example code:
#include <array>
using inarray_t = std::array<float,MY_INPUT_SIZE>;
using outarray_t = std::array<float,MY_OUTPUT_SIZE>;
// Change the signature of your function
void function(inarray_t&, outarray_t& , input_params);
// ...
int main() {
// ...
inarray_t input; // this is stack-allocated for performance reasons
outarray_t output; // this is stack-allocated for performance reasons
// ...
}
Take care that the stack allocations don't exceed the stack size limitations, these aren't that big usually, and you can end up with stack overflow (no pun intended) very quickly.

Related

Using static const string[] as a member instead of a global, initialized in the .cpp file

Related to this. I'd like to avoid using global variables so I resorted to using structs with enum and std::string[] (see link) in order to build menus for a small application. I would also like to have these enums in a separate header file. The selected answer in the link implies using --std=c++17, which I'd like to avoid, at least for now, and decided to use a static const std::string[] -- no need to include extra array or vector since this is initialized once, never modified, only called, ALL is always known.
As other answers on this have made it clear, I need to either initialize A::names outside the struct, or use a static const std::string& setter (see this, for example). But all the answers so far dealt with a std::string, not an array, std::string[].
This is a simple example of what I tried. It simply tries to print the contents of A::names using a for() loop iterating through the enum in struct A:
a.h:
#ifndef A_H_INCLUDED
#define A_H_INCLUDED
#include <string>
struct A
{
enum E { ONE, TWO, ALL };
static const std::string names[ALL];
};
#endif // A_H_INCLUDED
a.cpp:
#include "a.h"
static const std::string A::names[A::ALL] { "one", "two" };
main.cpp:
#include "a.h"
#include <iostream>
int main()
{
for(int i=A::ONE; i<A::ALL; ++i)
std::cout << A::names[i] << '\n';
return 0;
}
The error after g++ main.cpp is:
main.cpp:(.text+0x24): undefined reference to `A::names[abi:cxx11]'
collect2: error: ld returned 1 exit status
Seeing the cxx11, I thought g++ --std=c++11 main.cpp would solve it, but it doesn't.
So, what am I doing wrong, or, how could I adapt the version with the setter to return an array, std::string[]? My goal is to have an alternative to a global variable, that has only one instance in memory no matter how many calls.
Here's an adapted code, from a small program, on how I would build a menu using struct with enum and string (menu_design = new QMenu... and menuDesignAction() is the function that updates):
for(unsigned char i=0; i<A::ALL; ++i) // needs initializing
{
QAction *tmpAction {new QAction(tr(A::names[i].c_str()))};
tmpAction->setObjectName(QString("%1").arg(i));
connect(tmpAction, SIGNAL(triggered(bool)), this, SLOT(menuDesignAction()));
menu_design->addAction(tmpAction);
}
As a side-note, in the snippet above, I have to use .c_str(), but I am using a std::string in the enum. If I could make it *char[] instead of std::string[], would I avoid extra calls? If I am not wrong, how could the answers to my problem (assuming there are) be adapted so as to be able to fit somehow in the Qt snippet?

char variable has not been declared

I have ran into a problem yesterday when trying to split my code into several files.
Yesterday morning my whole code was in one file and to keep track of everything more easily I wanted to split the code into more files.
This went well until I got to a function where I need to declare a variable although I already have (but maybe in the wrong place).
Because the code is too long, I have put all files to pastebin.
I have declared "field" in main.cpp:
char field[20][41];
Whole file here: https://pastebin.com/Jy1XvdpL
And I want to use this in my field.cpp:
void loadLevel(int levelnumber) {
// concatenate leven base with level number
std::string level = "level" + std::to_string(levelnumber) + ".txt";
// print field
// load the text file
std::ifstream file;
file.open(level);
char c;
// read line by line, character by character and store it in field
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 41; j++) {
file.get(c);
field[i][j] = c;
}
}
file.close();
}
The field.h looks like this:
#ifndef field
#define field
#include <iostream>
#include <string>
#include <fstream>
void loadLevel(int levelnumber);
void drawField();
#endif // !field
The problem is that I do not know, where to define char field because I get an error if done in either of these files. So what do I need to do to get char field workin in field.cpp and therefore work in my main?
P.S. This is my first program in c++ and I am learning new things everyday. I appreciate any hints on how to do certain things better ^^
Kind Regards,
Benjamin
When you declare a variable in your main file, you are not able to use it in another file. (or at least easily)
if you wish to use your field variable in the field.cpp, then you can define it in field.h.
Code for this could be as followed.
#ifndef field
#define field
#include <iostream>
#include <string>
#include <fstream>
void loadLevel(int levelnumber);
void drawField();
char field[20][41];
#endif // !field
Though this will not allow you to use the information you assign to field[i][j] will not be available in your main file.
To do this I would make a function in field.h and field.cpp that returns the value of field[i][j].
You can use field array in your function by passing it as an argument to your loadlevel function, check this question too if you want to use pointers.
So your function will look like:
void loadLevel(int levelnumber,char field[][41]);

Plugins using Pluma

Overview
I am trying to develop a C++ application which allows for user-created plugins.
I found a nice library called Pluma (http://pluma-framework.sourceforge.net/) which functionally seems to be exactly what I want.
After going through their tutorial, I was able to (with a bit of difficulty) convince the plugin to compile. However, it refuses to play nice and connect with the main program; returning various errors depending on how I try to implement them.
Problem
If I comment out the line labeled 'Main problem line' (in the last file, main.cpp), the plugin compiles successfully, and the main app can recognize it, but it says that "Nothing registered by plugin 'libRNCypher'", and none of the functions can be called.
If I compile that line, the main application instead says "Failed to load library 'Plugins/libRNCypher.so'. OS returned error: 'Plugins/libRNCypher.so: undefined symbol: _ZTIN5pluma8ProviderE".
My guess is that it has something to do with the way the plugin was compiled, as compiling it initially did not work and Code::Blocks told me to compile with "-fPIC" as a flag (doing so made it compile).
Code
Code below:
Main.cpp
#include "Pluma/Pluma.hpp"
#include "CryptoBase.h"
int main()
{
pluma::Pluma manager;
manager.acceptProviderType< CryptoBaseProvider >();
manager.loadFromFolder("Plugins", true);
std::vector<CryptoBaseProvider*> providers;
manager.getProviders(providers);
return 0;
}
CryptoBase.h
#ifndef CRYPTOBASE_H_INCLUDED
#define CRYPTOBASE_H_INCLUDED
#include "Pluma/Pluma.hpp"
#include <string>
#include <vector>
#include <bitset>
//Base class from which all crypto plug-ins will derive
class CryptoBase
{
public:
CryptoBase();
~CryptoBase();
virtual std::string GetCypherName() const = 0;
virtual std::vector<std::string> GetCryptoRecApps() const = 0;
virtual void HandleData(std::vector< std::bitset<8> > _data) const = 0;
};
PLUMA_PROVIDER_HEADER(CryptoBase)
#endif // CRYPTOBASE_H_INCLUDED
RNCypher.h (This is part of the plugin)
#ifndef RNCYPHER_H_INCLUDED
#define RNCYPHER_H_INCLUDED
#include <string>
#include <vector>
#include <bitset>
#include "../Encoder/Pluma/Pluma.hpp"
#include "../Encoder/CryptoBase.h"
class RNCypher : public CryptoBase
{
public:
std::string GetCypherName() const
{
return "RNCypher";
}
std::vector<std::string> GetCryptoRecApps() const
{
std::vector<std::string> vec;
vec.push_back("Storage");
return vec;
}
void HandleData(std::vector< std::bitset<8> > _data) const
{
char letter = 'v';
_data.clear();
_data.push_back(std::bitset<8>(letter));
return;
}
};
PLUMA_INHERIT_PROVIDER(RNCypher, CryptoBase);
#endif // RNCYPHER_H_INCLUDED
main.cpp (This is part of the plugin)
#include "../Encoder/Pluma/Connector.hpp"
#include "RNCypher.h"
PLUMA_CONNECTOR
bool connect(pluma::Host& host)
{
host.add( new RNCypherProvider() ); //<- Main problem line
return true;
}
Additional Details
I'm compiling on Ubuntu 16.04, using Code::Blocks 16.01.
The second error message seems to not come from Pluma itself, but a file I also had to link, #include <dlfcn.h> (which might be a Linux file?).
I would prefer to use an existing library rather than write my own code as I would like this to be cross-platform. I am, however, open to any suggestions.
Sorry for all of the code, but I believe this is enough to reproduce the error that I am having.
Thank You
Thank you for taking the time to read this, and thank you in advance for your help!
All the best, and happy holidays!
I was not able to reproduce your problem, however looking at
http://pluma-framework.sourceforge.net/documentation/index.htm,
I've noticed that:
in your RNCypher.h file you miss something like
PLUMA_INHERIT_PROVIDER(RNCypher, CryptoBase)
it seems also that there's no file CryptoBase.cpp containing something like
#include "CryptoBase.h"
PLUMA_PROVIDER_SOURCE(CryptoBase, 1, 1);
finally, in CryptoBase.h I would declare a virtual destructor (see Why should I declare a virtual destructor for an abstract class in C++?) and provide a definition to it, while you should not declare a default constructor without providing a definition to it (see for instance Is it correct to use declaration only for empty private constructors in C++?); of course the last consideration is valid unless there's another file in which you have provided such definitions.

How can I make the contents of an #include-file a compile-time constant in a cpp-file?

I have a file module.hpp
struct ModuleBase {
virtual void run() = 0;
};
and a main.cpp program
int main() {
cout << ...?...; // here should go the contents of module.hpp
}
What can I put at ...?... to let the contents of the header file printed here?
A basic idea would be
int main() {
static const string content = R"(
#include <module.hpp>
)";
cout << content;
}
but multi-line-strings are only available in C++11, and #include does not work inside multi-line strings (which is good)?
If there is a non-portable way for the gcc... that would be a start.
Clarification (update): The substitution should be done at compile time.
The only real solution I know is to write a small program which
converts a file into a C++ definition of a string variable
containing it. This is fairly simple to write: output a simple
header along the lines of:
char const variableName[] =
Then copy each line of the file, wrapping it in "...\n", and
escaping any characters necessary. (If you can be sure of
C++11, then you might be able to do something with R"...", but
I've no experience with this.)
[update: refering to the original question with a typo in it]:
Your solution should not work; if it does, it is an error in
the compiler. According to ยง2.2, tokenization occurs before
the execution of preprocessing directives. So when the
execution of preprocessing directives occurs, you have a string
literal, and not a # preprocessing token. (Compiler errors
are to be expected when using C++11 features. There's not been
enough time yet for the implementers to get all of the bugs
out.)
As a GNU-only hack, you could convert the header into a binary object file and link that with the executable.
First, use objcopy to do the conversion:
objcopy -I binary -O default -B i386 module.hpp module.hpp.o
replacing i386 with the architecture you're building for if necessary. The resulting object file will contain symbols for the header contents and its size, which you can access as follows:
#include <iostream>
extern char _binary_module_hpp_start;
extern char _binary_module_hpp_size;
int main()
{
char * header_start = &_binary_module_hpp_start;
size_t header_size = reinterpret_cast<size_t>(&_binary_module_hpp_size);
std::cout.write(header_start, header_size);
}
Apart from external tools, I think it cannot be done. The C++11 way you given does not work, #include is not expanded in a string. See here for example.
The C++03 way would have been the following, with macros:
#define TO_STR__(...) #__VA_ARGS__
#define TO_STR_(...) TO_STR__(__VA_ARGS__)
#define TO_STR(...) TO_STR_(__VA_ARGS__)
#include <iostream>
int main()
{
std::cout << "String from #include <string>, ";
static const char* str = TO_STR(
#include <string>
);
std::cout << sizeof(str) / sizeof(char) << " characters:\n\n";
std::cout << str << "\n";
}
With GCC, nothing is outputed. With Visual Studio 2010, #include <string> is outputed.
If you can modify the compilation chain, you can add a prebuild step which will include the contents of the file you want as a string (can be done easily with tools like CMake, or custom makefile).
You can use ofstream to open a file stream and read and output the contents.

translate_address in c++\linux

i am trying to make user threads in C++, so while trying to initialize them i am getting a compiler error :translate_address was not declared in this scope
#include <iostream>
#include <cstdlib>
#include <csignal>
#include <csetjmp>
#define JB_SP 6 //Location in the code
#define JB_PC 7 //Stack pointer
#define STACK_SIZE 10
typedef unsigned long address_t; //64bit address
sigjmp_buf jbuf[3];
char stack1[STACK_SIZE];
void f(){
}
void setup(){
unsigned int sp, pc;
sp = (address_t)stack1 + STACK_SIZE - sizeof(address_t);
pc = (address_t)f;
sigsetjmp(jbuf[0],1);
(jbuf[0]->__jmpbuf)[JB_SP] = translate_address(sp);
(jbuf[0]->__jmpbuf)[JB_PC] = translate_address(pc);
sigemptyset(&jbuf[0]->__saved_mask);//empty saved signal mask
}
int main(){
return 1;
}
am i meant to include it some how? or is there a different problem?
thank you.
translate_address is not a Linux function. If you're referring to some kind of book or example code, it should explain where you're supposed to get this function from. If it doesn't, chances are it's not meant for Linux (or is a really, really bad reference/example).
Furthermore, you should NOT modify the contents of jmp_buf or sigjmp_buf directly. These are architecture and platform-dependent structures, and only the C library is allowed to mess with them. Since the contents of the structures are OS-dependent, if you're using a reference intended for some other OS when modifying sigjmp_buf, Bad Things will happen.
You should instead either use setcontext, getcontext, and makecontext for user threads (fibers) or pthread_create for OS-level threads.