(Not sure whether this is exclusively a C/C++ issue)
I’m currently fragmenting elements of a large Arduino project into reusable libraries - so far soo good.
However, a number of methods in the libraries return special structs which are declared in a data-types.h file contained in each library. The problem I have now is I'm unable to import/utilise these structs in my main sketch. I've tried declaring a variable of the DataTypes class in the main library header file and accessing the structs through it, but I get error error: invalid use of 'struct DataTypes::_theStructNameHere_t'
How would I go about accessing these structs from the library in my main sketch to declare as a variable type? I don't want to have to copy the header file which contains the structs from the library into my sketch, and I also don't want to have to create a separate library just for this single header file of structs!
Here's a quick example of what I mean:
Main.cpp:
#include <Arduino.h>
#include <MyLibrary.h>
MyLibrary myLib;
void setup() {
(This is declared in the library) myLib.dataTypes._theStructNameHere_t response = myLib.getASpecialValueWhichIsOfType_theStructNameHere_t()// Gives "error: invalid use of 'struct DataTypes::_theStructNameHere_t'""
// Example usage of the struct:
Serial.print("\n Loop Card Status: ");Serial.print(response.loop_status, HEX);
if (response.number_allocated > 0) {
Serial.print("\n Devices Allocated: ");Serial.print(response.number_allocated, HEX);
} else {
if (response.loop_status != 0x123) {
// Some condition
} else {
// Something else
}
}
}
void loop() {
...
}
Library Structure:
src/
- /data-types/
- - data-types.h
- MyLibrary.cpp
- MyLibrary.h
Library Header MyLibrary.h:
#ifndef _MYLIBRARY_H_
#define _MYLIBRARY_H_
#include <Arduino.h>
#include "./helpers/helpers.h"
...
#include "./data-types/data-types.h"
class MyLibrary {
public:
Uart *_commPort;
Helpers helpers;
...
DataTypes dataTypes;
DataTypes::_theStructNameHere_t getASpecialValueWhichIsOfType_theStructNameHere_t();
...
protected:
private:
};
#endif // _MYLIBRARY_H_
DataTypes Class data-types.h:
#ifndef _RESPONSE_TYPES_H
#define _RESPONSE_TYPES_H
class DataTypes
{
public:
struct _theStructNameHere_t
{
bool successful;
uint8_t loop_status;
uint8_t number_allocated;
uint8_t highest_address;
uint8_t number_inputs;
uint8_t number_outputs;
}
..even more..
private:
}
#endif // _RESPONSE_TYPES_H
I was able to obtain a MCVE from your example:
class DataTypes
{
public:
struct _theStructNameHere_t
{
};
};
class Library
{
public:
DataTypes dataTypes;
DataTypes::_theStructNameHere_t getMyDataType();
};
int main(int argc, char *argv[])
{
Library myLib;
myLib.dataTypes._theStructNameHere_t response;
}
which gives a similar error as your code:
~$ g++ test.cpp
test.cpp: In function 'int main(int, char**)':
test.cpp:20:21: error: invalid use of 'struct DataTypes::_theStructNameHere_t'
myLib.dataTypes._theStructNameHere_t response;
The problem is that you use an instance to access the struct type/name. To fix it, replace
myLib.dataTypes._theStructNameHere_t response = ...;
with
DataTypes::_theStructNameHere_t response = ...;
Notes:
Instead of using classes to create separate namespaces, please consider using namespaces directly. This is a feature of C++ which is available under Arduino.
namespace Library {
namespace DataTypes {
struct _theStructNameHere_t
{
...
};
...
} /*** namespace Library::DataTypes ***/
} /*** namespace Library ***/
Please read StackOverflow guidelines concerning how to ask a good question, in particular the section about Mininimal, Complete and Verifiable Example.
Sooner or later someone will tell you that there is no such thing as C/C++; C is C and C++ is C++; Arduino lives in its own world, even if is based on C++. Thus, you might want to remove C and C++ tags from your question.
Related
I am recently started reading about alsa api. I was trying to write a C++ class which opens default device and reads basic parameters like maximum rate, number of channels etc.
My class header file is:
#include <alsa/asoundlib.h>
#include <iostream>
class AlsaParam{
snd_pcm_t* pcm_handle;
snd_pcm_hw_params_t* hw_param;
....
public:
int pcm_open();
.....
};
Inside pcm_open()
int AlsaParam::pcm_open(){
int err = snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
if(err > -1)
std::cout << pcm_handle->name << std::endl; //Just to test if it works
return err;
}
I get following error:
error: invalid use of incomplete type ‘snd_pcm_t {aka struct _snd_pcm}’
std::cout << pcm_handle->name << std::endl;
^
In file included from /usr/include/alsa/asoundlib.h:54:0,
from alsa_param.h:4,
from alsa_param.cpp:1:
/usr/include/alsa/pcm.h:341:16: error: forward declaration of ‘snd_pcm_t {aka struct _snd_pcm}’
typedef struct _snd_pcm snd_pcm_t;
^
From this error I understood that asoundlib.h only uses typedef for struct snd_pcm_t but it is defined somewhere else. Am I correct? Is there any way to solve this problem? In general if we are including some c library functions in C++ class which are the things to remember/ avoid? Thanks
The layout of struct _snd_pcm is deliberately hidden from programs because it might change in a new library version.
To get a PCM device's name, call snd_pcm_name:
cout << snd_pcm_name(pcm_handle) << endl;
(Pretty much everything in ALSA needs such a function call.)
There is nothing wrong with your code. Just that there is missing declaration of struct _snd_pcm, the header you included only has the typedef: typedef struct _snd_pcm snd_pcm_t;
What you can do is look up (maybe on the internet or in the manual) for the header that hasstruct _snd_pcm declaration and include it in your code.
There are a few differences in declaration syntax between C and C++.
Since you're compiling a C++ file but including a C header inside it, you probably need to make the compiler interpret it the right way.
Try this:
extern "C"
{
#include <alsa/asoundlib.h>
}
#include <iostream>
class AlsaParam{
snd_pcm_t* pcm_handle;
snd_pcm_hw_params_t* hw_param;
...
I've read a few posts on here about static functions, but still am running into trouble with implementation.
I'm writing a hardcoded example of Dijkstra's algorithm for finding the shortest path.
Declared in Alg.h:
static void dijkstra();
Defined in Alg.cpp:
static void Alg::dijkstra() {
//Create Map
Initialize();
//Loop to pass through grid multiple times
for(int i=0; i<5; i++)
{
current=1;
while(current!=6)
{
//Iterate through and update distances/predecessors
//For loop to go through columns, while current iterates rows
for(int j=1; j<7; j++)
{
//Check if distance from current to this node is less than
//distance already stored in d[j] + weight of edge
if(distanceArray[current][j]+d[current]<d[j])
{
//Update distance
d[j] = distanceArray[current][j]+d[current];
//Update predecessor
p[j] = current;
}
}
//Go to next row in distanceArray[][]
current++;
} //End while
} //End for
output();
} //End Dijkstras
I want to call my function from main without an object. When I had all of this code in Main.cpp, it worked perfectly. Splitting it up into separate files caused the error Main.cpp:15: error: ‘dijkstra’ was not declared in this scope.The posts I came across when searching SE gave me me the impression that to do this, I needed to make that method static, yet I still have no luck.
What am I doing wrong?
Main.cpp:
#include <iostream>
#include "Alg.h"
int main() {
dijkstra();
return 0;
}
Edit: Added full header file, Alg.h:
#ifndef Alg_
#define Alg_
#include <iostream>
#include <stack>
using namespace std;
class Alg
{
public:
void tracePath(int x);
void output();
void printArray();
void Initialize();
static void dijkstra();
int current, mindex;
int distanceArray[7][7]; //2D array to hold the distances from each point to all others
int d[6]; //Single distance array from source to points
int p[6]; //Array to keep predecessors
int copyD[6]; //Copy of d[] used for sorting purposes in tracePath()
int order[6]; //Contains the order of the nodes path lengths in ascending order
}; //End alg class
#endif
Original all-in-one working Main.cpp file: http://pastebin.com/67u9hGsL
You should call it this way:
Alg::dijkstra();
Limitations
Can't call any other class functions that are not static.
Can't access non static class data members.
Can instantiate an object via new class() when constructor is private/protected. E.g. a factory function.
You can just use a namespace instead of having a class with all static members.
Alg.h:
namespace Alg
{
void dijkstra();
}
and in Alg.cpp
namespace Alg
{
void dijkstra()
{
// ... your code
}
}
in main.cpp
#include "Alg.h"
int argc, char **argv)
{
Alg::dijkstra();
return 1;
}
Are you sure the function is supposed to be static?
It looks as if you want just a function?
in your header file:
#ifndef DIJKSTRA_H
#define DIJKSTRA_H
void dijkstra();
#endif
in your cpp file
void dijkstra() {
/* do something */
}
in your main file:
#include "yourcppfile.h"
int main(int argc, char **argv) {
dijkstra();
}
if you really want a static function you have to put it into a nested class:
class Alg {
public:
static void dijkstra();
/* some other class related stuff */
}
the implementation somewhere in a cpp file
void Alg::dijkstra() {
/* your code here */
}
and then in your cpp file where the main resides
#include "your header file.h"
int main(int argc, char **argv) {
Alg::dijkstra();
}
If I remember right any 'static' function is limited to the module in which it is implemented. So, 'static' prevents using the function in another module.
In your header file Alg.h:
#ifndef __ALG_H__
#define __ALG_H__
namespace Alg {
void dijkstra();
}
#endif
The include guards are necessary if you plan to include the header in more than one of your cpp files. It seems you would like to put the function in a namespace Alg, right?
In Alg.cpp:
#include "Alg.h"
void Alg::dijkstra() { /* your implementation here */ }
Then, in main.cpp you call it with full namespace qualification:
#include "Alg.h"
int main() {
Alg::dijkstra();
}
If you just want to distribute your code over several files, I don't see why the function should be declared static.
You are confusing the 'static' keyword for local functions, with the 'static' keyword used in a class to make a function a class function and not an object function.
Remove static the first line of Alg.cpp and in the header file. This will allow Alg.o to contain global symbols that main can refer to and the linker can link.
You still need to call Alg::dijkstra() as was stated by #egur.
After this you may still get errors. The way you are using Alg:: is more like a namespace than a 'class' definition.
Now that we have the complete declaration of your class Arg, it feels like the singleton design pattern could be useful:
http://en.wikipedia.org/wiki/Singleton_pattern
The key here is the ‘dijkstra’ was not declared in this scope error.
Take your all-in-one source file and remove the main function. Make a new source file with this in it:
void dijkstra();
void output();
int main(int argc, char *argv[]) {
dijkstra();
output();
return 0;
}
The all-in-one cpp without a main plus this file above should compile together and give you the same result as before with one source, as it does for me. You will get a duplicate symbol _main error if you forgot to remove the main from the algorithm file.
No static needed.
My answer here fails to touch on good practices on header files, that is, you would want to include those function declarations in a .h file. It solves the compile-time error though.
You may want to find a good book to help you through some of the machinery of C++, where program context (in a linguistic sense) can change the meaning of keywords. This can be bewildering, and it proves to be exactly that for a language with as much colorful history as C++. Take a look here for book suggestions.
I am writing file conversion code from a proprietary file format to one more generic. My goal is to support multiple versions of the manufacturer's file format.
I have a multiple versions of the same proprietary headers. The headers define various structs which comprise the main file header (the file is simply a large header followed by raw data).
I need to read the first 4 bytes of the source file to determine the file version. The file version, in turn, tells me which version of the C-structs was used to create the file.
The issues are:
I can't modify the proprietary headers
The headers do not use namespaces or classes
There are a good handful of macros defined in the headers
Possible solutions:
Build different converter binaries for each file version type :-(
Inconvenient for both user and developer
Dynamically load libraries for each version
The converter is plugin-oriented, so there's already a lot of this happening
I have tried hacking with namespaces:
namespace version1 {
#include "version1.h"
}
namespace version2 {
#include "version2.h"
}
int main (void) {
version1::header *hdr = new version1::header;
return 0;
}
But this won't work because of include guards, and because there are multiple macros are redefined in each header.
Is there an elegant way to handle this?
You could use two different source files, together with a forward declaration:
// Forward declare in main.cpp:
namespace version1
{
struct header;
}
namespace version2
{
struct header;
}
// version1.cpp:
namespace version1
{
#include <version1.h>
}
version1::header* new_v1_header()
{
return new version1::header;
}
// other functions using `version1::header`
// version2.cpp:
namespace version2
{
#include <version2.h>
}
version2::header* new_v2_header()
{
return new version2::header;
}
// other functions using `version2::header`
Another alternative is to implement a wrapper class, which has a base-class that is just an empty shell:
class header_base
{
virtual int func1(char *stuff) = 0;
... many other virtual functions.
};
// Create implementation of header_v1 or header_v2:
header_base* make_header(unsigned int magic);
header_base.cpp:
#include "header_v1.h"
#include "header_v2.h"
header_base* make_header(unsigned int magic)
{
switch(magic)
{
case Magic_V1:
return new header_v1;
case Magic_V2:
return new header_v2;
default:
assert(0);
return 0;
}
}
and then implement, in two separate
in headerv1.h:
class header_v1 : public header_base
{
int func1(char *stuff);
...
};
header_v1.cpp:
#include "header1.h"
int header_v1::func1(char *stuff)
{
...
return 17;
}
And similar for header_v2.h and header_v2.cpp.
I have some code that I wanted to put into a library which uses another library, SoftwareSerial. Now I added the SoftwareSerial.h and SoftwareSerial.cpp files to the same folder as the library I'm creating.
My header file looks something like this:
#ifndef MyLibrary_h
#define MyLibrary_h
#include "Arduino.h"
#include "SoftwareSerial.h"
#define MyLibrary_VERSION 1 // software version of this library
//DEFINE ALL CLASS VARIABLES
#define DATA_BUFFER_SIZE 50 //soft serial has 63 byte buffer.
class MyLibrary
{
public:
MyLibrary(uint8_t port_in, uint8_t port_out);
float getSomeValue(uint8_t some_index);
private:
SoftwareSerial _serial;
//Not sure if I should add the constructors below to the above declaration.
//(uint8_t in_pin=4, uint8_t out_pin=5, bool logic_reversed = false);
float convertSomeValue(byte upperbyte, byte lowerbyte);
void flushSerialBuffer();
};
#endif
My .cpp file looks like this:
#include "Arduino.h"
#include "MyLibrary.h"
#include "SoftwareSerial.h"
MyLibrary::MyLibrary(uint8_t in_pin, uint8_t out_pin)
{
bool logic_reversed = false;
this->_serial(in_pin*, out_pin*, logic_reversed);
//I tried the declaration below as well.
//SoftwareSerial _serial(in_pin*, out_pin*, logic_reversed);
}
float MyLibrary::getSomeValue(uint8_t sensor_index) {
float someValue = 1.1;
return someValue;
}
float MyLibrary::convertSome(byte upperbyte, byte lowerbyte) {
float someValue = 0.9;
return someValue;
}
void MyLibrary::flushSerialBuffer() {
//Flush serial buffer
while(_serial.available())
char c = _serial.read();
}
I would like SoftwareSerial to be a private field in MyLibrary (preferably static but not necessary) but I've tried many was of declaring it but nothing seems to work. I keep getting errors like no matching function for call to 'SoftwareSerial::SoftwareSerial() or invalid use of qualified-name 'MyLibrary::_serial'.
I got it to compile fine once by declaring static SoftwareSerial _serial; in my .h file, and SoftwareSerial MyLibrary::_serial(4,5,false); at the top of my .cpp file. The thing is, I would like to set the ports of _serial in my constructor for MyLibrary (so I can create a MyLibrary that uses specific in/out pins for SoftwareSerial) and not have them explicitly declared at the top of the .cpp file.
I'm not so familiar with C coding and Arduino so it would be a great help if someone could explain to me how to declare these properly in the .h file and instanciate them with the correct ports in the MyLibrary constructor or a MyLibrary.begin() function (or something of the like).
Thanks in advance for you helpful comments.
What you need is to make your constructor do the initialization as follows:
class MyLibrary{
public:
MyLibrary(uint8_t, uint8_t);
//...
private:
SoftwareSerial _serial;
//...
};
MyLibrary::MyLibrary(uint8_t in, uint8_t out)
: _serial(in, out)
{
//do initialization
}
This syntax might seem strange at first, but although it isn't quite as pretty, it clearly differentiates initialization of variables vs operations on variables, which is something that placing the initialization in the body of the constructor can make slightly fuzzy. As a rule, UNLESS you use this syntax to initialize a member variable, C++ will call the default constructor, which will cause a compile error iff the member does not have a callable default constructor.
The biggest problem I seem to run into when coding in c++ is the fact that you must declare a class before you can reference it. Say I have two header file like this...
Header1.h
#include "Header2.h"
#include <deque>
#include <string>
#include <iostream>
using namespace std;
class HelloPackage;
class Hello
{
public:
string Message;
HelloPackage * Package;
Hello():Message("")
{
}
Hello(string message, HelloPackage * pack)
{
Message = message;
Package = pack;
}
void Execute()
{
cout << Message << endl;
//HelloPackage->NothingReally doesn't exist.
//this is the issue essentially
Package->NothingReally(8);
}
};
Header2.h
#include "Header1.h"
#include <deque>
#include <string>
#include <iostream>
using namespace std;
class HelloPackage
{
public:
deque<Hello> Hellos;
HelloPackage()
{
Hellos = deque<Hello>();
}
int AddHello(string Message)
{
Hellos.push_back(Hello(Message,this));
}
void ExecuteAll()
{
for each(Hello h in Hellos)
h.Execute();
}
int NothingReally(int y)
{
int a = 0;
a += 1;
return a + y;
}
}
What I'm wondering is, is there any elegant solution for dealing with these issues? In say c#, and java, you're not restricted by this "linear" compiling.
Use header include guards, either "#ifndef / #define / #endif", or "#pragma once"
Put your code in a .cpp, not inline in the header
???
Profit
The reason this will work for you is because you can then use forward declarations of the class you want to reference without including the file if you so wish.
You are missing include guards
why define methods in the header?
Besides these problems with your code, to answer your question : normal way is to forward declare classes - not to include headers in headers (unless you have to).
If you follow a few basic rules, it is not awkward at all. But in comparison to e.g. Java or C#, you have to follow these rules by yourself, the compiler and/or language spec does not enforce it.
Other answers already noted that, but I will recap here so you have it in one place:
Use include guards. They make sure that your header (and thus your class definition) is only included once.
Normally, you will want to separate the declaration and implementation of your methods. This makes the header files more reusable and will reduce compilation time, because the header requires normally fewer #includes than the CPP (i.e. implementation) file.
In the header, use forward declarations instead of includes. This is possible only if you just use the name of the respective type, but don't need to know any "internals". The reason for this is that the forward declaration just tells the compiler that a certain name exists, but not what it contains.
This is a forward declaration of class Bar:
class Bar;
class Foo {
void foooh(Bar * b);
};
Here, the compiler will know that there is a Bar somewhere, but it does not know what members it has.
Use "using namespace xyz" only in CPP files, not in headers.
Allright, here comes your example code, modified to meet these rules. I only show the Hello class, the HelloPackage is to be separated into header and CPP file accordingly.
Hello.h (was Header1.h in your example)
#include <string>
class HelloPackage;
class Hello
{
public:
Hello();
Hello(std::string message, HelloPackage * pack);
void Execute();
private:
string Message;
HelloPackage * Package;
};
Hello.cpp
#include "Hello.h"
#include "HelloPackage.h"
using namespace std;
Hello::Hello() : Message("")
{}
Hello::Hello(string message, HelloPackage * pack)
{
Message = message;
Package = pack;
}
void Hello::Execute()
{
cout << Message << endl;
// Now accessing NothingReally works!
Package->NothingReally(8);
}
One question that may arise is why is the include for string is needed. Couldn't you just forward declare the string class, too?
The difference is that you use the string as embedded member, you don't use a pointer to string. This is ok, but it forces you to use #include, because the compiler must know how much space a string instance needs inside your Hello class.