I'm new in C++, and have been given a (relatively) complex piece of code.
I want to call a function transmit() from a .h file in another .c file.
The transmit() is in the file serviceUart.hpp which content looks like this:
serviceUart.hpp
class ServiceUart
{
public:
ServiceUart();
void ioConfig(); // sets io HW ports and pins. Only needed at first boot
void ioInit(); //
bool readTrigger();
bool detectConnection() {return (m_rxPin.get()|| m_enabled);}
bool startup();
bool transmit(const char* s, uint16_t length, bool wait = false);
The file drvr.cpp is where I try calling the function. A snippet of what I think is relevant from that file looks like this:
drvr.cpp
#include "EHS5_drv.hpp"
char debug[] = "I got to here!";
transmit(debug,true);
I tried serviceUart.transmit and serviceUart::transmit, but no matter what I try, I get the error code `#20 identifier "transmit" is undefined". I guess I'm misunderstanding the syntax?
Method bool transmit(const char* s, uint16_t length, bool wait = false); is defined in ServiceUart. You have to create an object of ServiceUart class and then call method transmit()
char debug[] = "I got to here!";
ServiceUart obj;
obj.transmit(debug,true);
Or with new
ServiceUart* obj = new ServiceUart();
obj->transmit(debug,true);
delete obj;
Don't forget to delete obj.
You probably want:
char[] debug = "I got here";
ServiceUart serviceObg;
obj.transmit(debug, true);
Related
I want to make my code more efficient, specifically the reading of data from a text file. Here is a snapshot of what it looks like now:
values V(name);
V.population = read_value(find_line_number(name, find_in_map(pop, mapping)));
V.net_growth = read_value(find_line_number(name, find_in_map(ngr, mapping)));
... // and so on
Basically, the read_value function creates an ifstream object, opens the file, reads one line of data, and closes the file connection. This happens many times. What I want to do is to open the file once, read every line that is needed into the struct, and then close the file connection.
Here is the creating values struct function with parameters:
static values create_struct(std::string name, std::map<std::string, int> mapping) {
values V(name);
V.population = read_value(find_line_number(name, find_in_map(pop, mapping)), file);
V.net_growth = read_value(find_line_number(name, find_in_map(ngr, mapping)), file);
// more values here
return V;
}
The function that calls create_struct is shown below:
void initialize_data(string name) {
// read the appropriate data from file into a struct
value_container = Utility::create_struct(name, this->mapping);
}
I am thinking of instead defining the ifstream object in the function initialize_data. Given what is shown about my program, would that be the best location to create the file object, open the connection, read the values, then close the connection? Also, would I need to pass in the ifstream object into the create_values struct, and if so, by value, reference or pointer?
The short answer is to create your ifstream object first and pass it as reference to your parser. Remember to seek the stream back to the beginning before you leave your function, or when you start to read.
The RAII thing to do would be to create a wrapper object that automatically does this when it goes out of scope.
class ifStreamRef{
ifStreamRef(std::ifstream& _in) : mStream(_in){}
~ifStreamRef(){mStream.seekg(0);}
std::ifstream& mStream;
}
Then you create a wrapper instance when entering a method that will read the fstream.
void read_value(std::ifstream& input, ...){
ifStreamRef autoRewind(input);
}
Or, since the Ctor can do the conversion...
void read_value(ifStreamRef streamRef, ...) {
streamRef.mStream.getLine(...);
}
std::ifstream itself follows RAII, so it will close() the stream for you when your stream goes out of scope.
The long answer is that you should read up on dependency injection. Don't create dependencies inside of objects/functions that can be shared. There are lots of videos and documents on dependency injection and dependency inversion.
Basically, construct the objects that your objects depend on and pass them in as parameters.
The injection now relies on the interface of the objects that you pass in. So if you change your ifStreamRef class to act as an interface:
class ifStreamRef{
ifStreamRef(std::ifstream& _in) : mStream(_in){}
~ifStreamRef(){mStream.seekg(0);}
std::string getLine(){
// todo : mStream.getLine() + return "" on error;
}
bool eof() { return mStream.eof(); }
std::ifstream& mStream;
}
Then later on you can change the internal implementation that would take a reference to vector<string>& instead of ifstream...
class ifStreamRef{
ifStreamRef(std::vector<string>& _in) : mStream(_in), mCursor(0){}
~ifStreamRef(){}
std::string getLine(){
// todo : mStream[mCursor++] + return "" on error;
}
bool eof() { return mCursor >= mStream.size(); }
std::vector<string>& mStream;
size_t mCursor;
}
I have oversimplified a few things.
So, I am trying to log information about the status of the c++ project code in a text file. The program terminates unexpectedly, so I need to append the file as I go rather than storing info in an array along the way. I wanted to call the function to write to the file from within other functions, eventually in the other c++ files as well.
The code is a huge project that has many files and the "main()" technically exists in a separate file from all of the functions that are called throughout the function of the code (therefore not a useful file for me). My plan was to open the file in the setup() function, and then call the function within other functions along the way. Just in case I did not explain the setup of the code well enough, here is the link to the file I am trying to add to: https://github.com/cstracq2/ardupilot/blob/master/ArduCopter/ArduCopter.cpp
I have seen other notes on what may help, but I am not that familiar with c++ and I don't know what most of it means. From what I saw, this is one of the ways I tried, and it is failing to compile.
#include "<existing header>.h"
#include <fstream>
#include <iostream>
void log_data( ofstream &datafile, int value);
void <>::function1()
{ ....<stuff that was already there>
log_data( datafile, <value> );
}
void <>::function2()
{ ....<stuff that was already there>
log_data( datafile, <value> );
}
void setup()
{ ....<stuff that was already there>
ofstream datafile;
datafile.open("data_log_file.txt");
}
void log_data( ofstream &datafile, int value)
{
data_file << value << endl;
}
If there is any advice that you could give me, I would really appreciate it.
In your case I would suggest to use the Singleton Pattern. Here is an example of how you could do it:
class Logger
{
std::ifstream logF;
static Logger *s_instance;
Logger(std::string &path)
{
logF.open(path, std::ios_base::in);
}
public:
void log_data(int val)
{
logF << val << std::endl;
}
static void create_instance(std::string &path)
{
s_instance = new Logger(path);
}
static Logger *instance()
{
return s_instance;
}
};
Now you can just include the header with the class def and call something like:
Logger::instance()->log_data(<value>);
And do not forget to init the class before calling the static method (somewhere in main for instance):
Logger::create_instance(<path>);
Of course, you can just make it easier by hard-coding a value for your path, but if the path changes you'll have to re-compile everything.
Or just use something already implemented like log4cpp
Ah yes now that you mentioned the use of datafile in other function I see the error: The variable datafile is a local variable inside the setup function.
It should either be a member variable or possible a global variable.
I found this question answered for Python, Java, Linux script, but not C++:
I'd like to write all outputs of my C++ program to both the terminal and an output file. Using something like this:
int main ()
{
freopen ("myfile.txt","w",stdout);
cout<< "Let's try this";
fclose (stdout);
return 0;
}
outputs it to only the output file named "myfile.txt", and prevents it from showing on the terminal. How can I make it output to both simultaneously? I use visual studio 2010 express (if that would make any difference).
Thanks in advance!
Possible solution: use a static stream cout-like object to write both to cout and a file.
Rough example:
struct LogStream
{
template<typename T> LogStream& operator<<(const T& mValue)
{
std::cout << mValue;
someLogStream << mValue;
}
};
inline LogStream& lo() { static LogStream l; return l; }
int main()
{
lo() << "hello!";
return 0;
}
You will probably need to explicitly handle stream manipulators, though.
Here is my library implementation.
There is no built in way to do this in one step. You have to write the data to a file and then write the data out on screen in two steps.
You can write a function that takes in the data and the filename and does this for you, to save you time, some sort of logging function.
I have a method to do this, and it is based on a subscriber model.
In this model all your logging goes to a "logging" manager and you then have "subscribers" that decide what to do with the messages. Messages have topics (for me a number) and loggers subscribe to one or more topic.
For your purpose, you create 2 subscribers, one that outputs to the file and one that outputs to the console.
In the logic of your code you simply output the message, and at this level not need to know what is going to be done with it. In my model though you can check first if there are any "listeners" as this is considered cheaper than constructing and outputting messages that will only end up in /dev/null (well you know what I mean).
One way to do this would be to write a small wrapper to do this, for example:
class DoubleOutput
{
public:
// Open the file in the constructor or any other method
DoubleOutput(const std::string &filename);
// ...
// Write to both the file and the stream here
template <typename T>
friend DoubleOutput & operator<<(const T& file);
// ...
private:
FILE *file;
}
To have a class instead of a function makes you use the RAII idiom (https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization)
To use it:
DoubleOutput mystream("myfile");
mystream << "Hello World";
I have some class with Load() function, for example.
class DB {
private:
pt_db *db;
public:
DB(const char *path);
Write(const char *path);
int Load(const char *path);
};
And I want to return some status from Load() function depending on the passed argument.
For example:
Load(<correct path to the file with valid content>) // return 0 - success
Load(<non-existent path to file>) // return 1
Load(<correct file path, but the content of the file is wrong>) // return 2
Nevertheless also I'm worrying about:
Type safety - I mean I want to return some object which could only be used as status code.
int res = Load(<file path>);
int other = res * 2; // Should not be possible
Use only predefined values. With int I can return, by error, some other status like return 3 (let's suggest something wrong has happened in Load() function) and if I don't expect this error code will be passed:
int res = Load(<file path>);
if(res == 1) {}
else if (res == 2) {};
...
// Here I have that code fails by reason that Load() returned non-expected 3 value
Use best C++11 practises about it.
Could anyone help?
Enums would be a good way to return status for example:
class Fetcher{
public:
enum FetchStatus{ NO_ERROR, INVALID_FILE_PATH, INVALID_FILE_FORMAT };
private:
FetchInfo info;
public:
FetchStatus fetch(){
FetchStatus status = NO_ERROR;
//fetch data given this->info
//and update status accordingly
return status;
}
};
Another way would be to use exceptions
class Fetcher{
private:
FetchInfo info;
public:
void fetch(){
if file does not exist throw invalid file path exception
else if file is badly formatted throw invalid file format exception
else everything is good
}
Using enums as return status is more C way and using exceptions might be more C++ way, but its a matter of choice. I like the enum version as it is less code and more readable in my opinion.
I have two functions read() and write(). I read a file in the read() function and store a line in the header in a variable. Now i want the write() function to write that same line to a new file. But how can i use the same variable or information from the other function? What is the way to do this?
Here is some info about the code:
After including necessary files, it says this
HX_INIT_CLASS(HxCluster,HxVertexSet);
The name of the class is HxCluster and it would be great if someone can tell me why it is not like we define classes in the simple way: class class_name {};
The I have many functions out of which two are read() and write(). They both take one argument only which is the file to be read and the file to be written to in the respective cases. I don't know if writing the code for that will help here.
If I understood you well, this is just what in C++ the structures/classes/objects are for. For example:
class FileLineWriter
{
public:
FileLineWriter();
void read(istream& inputfile);
void write(ostream& putfile);
private:
string line_of_text;
};
void FileLineWriter::read(istream& s)
{
// s >> this->line_of_text; // possible, but probably will not do what you think
getline(s, this->line_of_text);
}
void FileLineWriter::read(ostream& s)
{
s << this->line_of_text;
}
...
FileLineWriter writer;
writer.read(firstfile);
writer.write(secondfile);
note that the above is NOT a working code. It is just a sample. You will have to fix all typos, missing namespaces, headers, add stream opening/closing/error handling, etc.
You return the variable from read and pass it as a parameter to write. Something like this
std::string read()
{
std::string header = ...
return header;
}
void write(std::string header)
{
...
}
std::string header = read();
write(header);
Passing information between functions is a basic C++ skill to learn.
If I have understood this right then I would suggest that you save the info on the variable to a string or an int depending on what kind of info it is.
I would also recommend to always include some code for us to be able to give you some more help
You can either make write take an argument, void write(std::string text) or you can store the string you read as a global variable std::string text at the top of your .cpp file, text = ... in your read function (replace ... with ifstream or whatever you use) and then write text in your write funcion.
Sure,
Use pointers!
void main(){
char* line = malloc(100*sizeof(char));
read_function (line);
write_function (line);
}
void read_function(char* line){
.... read a line
strcpy (line, the_line_you_read_from_file);
}
void write_function (char* line){
fprintf (fp,"%s", line);
}