This question already has answers here:
What is the reason for not being able to deduce array size from initializer-string in member variable?
(3 answers)
In class default initializer for array member C++11
(1 answer)
Closed 5 days ago.
The community is reviewing whether to reopen this question as of 5 days ago.
I'm building a LED control class for ESP32 using Arduino IDE and I'm facing problems regarding structuring its properties:
Reproducible example HERE
LEDS CLASS:
Leds.h
#pragma once
#include <Arduino.h>
enum LedState {
LED_OFF,
LED_ON,
LED_BLINK,
LED_PULSE
};
typedef struct {
char name[32];
int pin;
LedState state;
int start;
int delay;
int blinkCount;
} Led;
#define MAX_LEDS 50
class Leds
{
private:
Led leds[MAX_LEDS];
public:
void setup();
void loop();
};
Leds.cpp
#include "Leds.h"
void Leds::setup()
{
// some setup code here
}
void Leds::loop()
{
// put your main code here, to run repeatedly:
}
The Leds class is used in a config class, as follows:
CONFIG CLASS:
Config.h
#pragma once
#include "Leds.h"
class Config
{
public:
Led leds[] = {
{"status", 2, LED_OFF, 0, 0, 0},
{"test", 3, LED_OFF, 0, 0, 0},
};
void setup();
};
Config.cpp
#include <Arduino.h>
#include "Config.h"
void Config::setup()
{
// Do something here
}
When compiling I'm getting the following error:
src/Config.h:13:5: error: flexible array member 'Config::leds' in an otherwise empty 'class Config'
};
^
As far as I understood the Led struct has a fixed size - so no idea why I'm getting this error and how to solve it.
Related
I have a C++ program with an undefined reference error on the call of a method in a class. As near as I can tell, the method is public and I'm calling it with a parameter declared the same as the method definition, but eclipse/gcc tells me it is undefined. I'm not used to C++, can someone please tell me what's wrong with the definition?
The main class:
#include <iostream>
using namespace std;
#include "AttenuationConfigurationTable.h"
int main()
{
flash_entry_struct flash_array[] = { { 10, 20, 30, 40 }, { 50, 60, 70, 80 }, { -1, -1, -1, -1 } };
// note: no undefined reference or any other error for the line with the class
AttenuationConfigurationTable attConfigTable;
// error appears for next line: undefined reference to ...load_attenuation_...
attConfigTable.load_attenuation_calibration_table_from_flash(flash_array);
return 0;
}
The class file:
#include "AttenuationConfigurationTable.h"
#include "flashEntryStruct.h"
AttenuationConfigurationTable::AttenuationConfigurationTable() { }
AttenuationConfigurationTable::~AttenuationConfigurationTable() { }
class Attenuation_configuration_table
{
struct attenuation_voltages_struct
{
float att_value;
float v1;
float v2;
} ;
struct frequency_tables_struct
{
int frequency;
attenuation_voltages_struct attenuation_voltages[100];
int voltages_count = 0;
} ;
frequency_tables_struct _frequency_tables[42];
public:
/************************************************************************/
/* load the table in this object from the given flash memory address */
/************************************************************************/
void load_attenuation_calibration_table_from_flash(flash_entry_struct memory_address[])
{
// bunch of logic here...
}
};
The h file for the class:
#ifndef ATTENUATIONCONFIGURATIONTABLE_H_
#define ATTENUATIONCONFIGURATIONTABLE_H_
#include "flashEntryStruct.h"
class AttenuationConfigurationTable
{
public:
AttenuationConfigurationTable();
virtual ~AttenuationConfigurationTable();
void load_attenuation_calibration_table_from_flash(flash_entry_struct flash_memory_address[]);
};
#endif /* ATTENUATIONCONFIGURATIONTABLE_H_ */
And, just for completeness, the h file defining the parameter structure:
#ifndef FLASHENTRYSTRUCT_H_
#define FLASHENTRYSTRUCT_H_
struct flash_entry_struct
{
uint16_t frequency;
uint16_t scaled_db;
int8_t v1_byte;
int8_t v2_byte;
} ;
#endif /* FLASHENTRYSTRUCT_H_ */
EDIT: the error message itself:
Invoking: Cygwin C++ Linker
g++ -o "HelloCPP.exe" ./src/AttenuationConfigurationTable.o ./src/Hello2.o ./src/HelloCPP.o
/usr/lib/gcc/x86_64-pc-cygwin/10/../../../../x86_64-pc-cygwin/bin/ld: ./src/HelloCPP.o:/cygdrive/c/Users/ralph/files/programming/workspaces/HelloCPP/HelloCPP/Debug/../src/HelloCPP.cpp:15: undefined reference to `AttenuationConfigurationTable::load_attenuation_calibration_table_from_flash(flash_entry_struct*)'
collect2: error: ld returned 1 exit status
make: *** [makefile:58: HelloCPP.exe] Error 1
"make all" terminated with exit code 2. Build might be incomplete.
You declare AttenuationConfigurationTable in the header file with the load_attenuation_calibration_table_from_flash function, but then the function with the same name in the implementation file is inside the definition for another class, Attenuation_configuration_table.
Take the implementation for load_attenuation_calibration_table_from_flash out of the class definition for Attenuation_configuration_table in your cpp file, and define it instead as
void AttenuationConfigurationTable::load_attenuation_calibration_table_from_flash(/* ... */) {
// ...
}
This is the same syntax already used for the constructor and destructor in that file.
In the end, your header should look something like this:
class AttenuationConfigurationTable
{
public:
AttenuationConfigurationTable();
virtual ~AttenuationConfigurationTable();
void load_attenuation_calibration_table_from_flash(flash_entry_struct flash_memory_address[]);
private:
struct attenuation_voltages_struct
{
float att_value;
float v1;
float v2;
} ;
struct frequency_tables_struct
{
int frequency;
attenuation_voltages_struct attenuation_voltages[100];
int voltages_count;
} ;
frequency_tables_struct _frequency_tables[42];
};
and your cpp file should look something like this:
AttenuationConfigurationTable::AttenuationConfigurationTable() { }
AttenuationConfigurationTable::~AttenuationConfigurationTable() { }
void AttenuationConfigurationTable::load_attenuation_calibration_table_from_flash(/* params */) {
// body
}
Hey guys I'm getting this error when compiling in Arduino IDE
error: no 'void sim::sendSMS(char*)' member function declared in class 'sim'
void sim::sendSMS(char msg[160])
My Header file is:
#ifndef sim_h
#define sim_h
#include "Arduino.h"
class sim
{
public:
sim();
void smstextmode();
void testSIM900();
void sendSMS(char _msg[160]);
private:
char _msg[160];
};
#endif
My CPP file:
#include "Arduino.h"
#include "sim.h"
sim::sim()
{
_msg= msg;
}
void sim::smstextmode()
{
Serial1.write("AT+CMGF=1\r\n");
delay(2000);
}
void sim::testSIM900()
{
Serial1.write("AT\r\n");
delay(1000);
Serial1.write("AT+CSCS?\r\n");
delay(1000);
}
void sim::sendSMS(char msg[160])
{
Serial1.write("AT+CMGS=\"+8295724554\"\r\n");
delay(1500);
Serial1.write(msg);
delay(1000);
Serial1.write((char) 26)
}
So many mistakes. For example:
sim::sim()
{
_msg= msg; // where it should get this msg?
// Also it's not possible to do a copy of array like this.
}
Why do you need _msg, if you are sending msg passed as a parameter?
void sim::sendSMS(char msg[160])
If you want to call it, you have to use exactly the same data type:
char something[160] = "some text to send";
instance.sendSMS(something);
But you can't just pass string directly:
instance.sendSMS("some text to send");
as it's type of const char * and it can't be handled by type char[160].
Also you don't count with termination characte at the end of the string.
This question already has answers here:
Static Data Member Initialization
(7 answers)
Closed 7 years ago.
I am making a program for arduino. I am using avr-g+ 4.9.2 with STL from here.
I have a class Cocktail. I want all objects of type Cocktail to be able to access a vector of pointers. These pointers point to objects of type Alcohol. Seeing as this vector of pointers is the same for each instance of Cocktail, I wanted to make it static. But then my program fails to compile if I make them static. Here is the code:
Ineb.hpp
class Alcohol
{
private:
float flow_rate_;
Pump * which_pump_;
public:
std::string this_alcohol_;
Alcohol(std::string this_alcohol, float flow_rate);
Alcohol(std::string this_alcohol, float flow_rate, Pump which_pump);
float HowLong(float percentage_of_drink, uint8_t drink_size); //How long in seconds the pump should be on
void ChangeByteToRegister(uint8_t& byte_to_register);
};
class Cocktail
{
private:
bool order_matter_;
uint8_t byte_to_register_;
static std::vector<Alcohol*> alcohol_directory_;
public:
static void test(Alcohol *ba) {alcohol_directory_.push_back(ba);} //STATIC KEYWORD HERE
Cocktail(bool ordr_matter);
std::vector<std::string> GetIngredients(const uint8_t& num_ingredients, PGM_P& string_table);
uint8_t GetByteToRegister();
void MakeDrink(const uint8_t& num_ingredients, PGM_P& string_table);
};
main.cpp
#include "src/Ineb.hpp"
#include "src/Pins.hpp"
#include "ingredients.h"
#include <pnew.cpp>
extern "C" void __cxa_pure_virtual() {
for(;;);
}
int main(void) {
init();
setup();
Ineb::Pump A(1,8);
Ineb::Alcohol Vodka("vodka", 2.5, A);
Ineb::Cocktail::test(&Vodka);
for(;;)
loop();
return 0; // not reached
}
undefined reference to `Ineb::Cocktail::alcohol_directory_'
I'm mainly confused why this compiles when I take away static. What is static doing under the hood??
static members of classes must be defined outside the class definition.
Having the line
std::vector<Alcohol*> Cocktail::alcohol_directory_;
in Cocktail.cpp will do it.
I'm using the Arduino IDE 1.0.5-r2 and trying to create a class with two member variables, _pinA and _pinB. When I call the constructor from my Arduino sketch, I get this error:
RotaryEncoderReader.cpp:6: error: request for member '_pinB' in 'this', which is of non-class type 'RotaryEncoderReader* const'
The constructor can be called from a regular C++ files compiled using GCC, and there are no errors. Am I missing something about how to use a class constructor with an Arduino?
Here is the class header:
#ifndef RotaryEncoderReader_h
#define RotaryEncoderReader_h
#include "Arduino.h"
class RotaryEncoderReader {
private:
int _pinA;
int _pinB;
volatile long encoderPos;
public:
RotaryEncoderReader( int newPinA, int newPinB );
void doEncoderA();
void doEncoderB();
long getPosition();
};
#endif
Here's the implementation:
#include "RotaryEncoderReader.h"
RotaryEncoderReader::RotaryEncoderReader( int newPinA, int newPinB )
: _pinA(newPinA),
_pinB(newPinB),
encoderPos(0)
{
}
void RotaryEncoderReader::doEncoderA()
{
//Irrelevant
}
void RotaryEncoderReader::doEncoderB()
{
//Irrelevant
}
long RotaryEncoderReader::getPosition()
{
return _pinA + _pinB;
}
And here's the Arduino sketch:
#include <RotaryEncoderReader.h>
int pinA = 2;
int pinB = 3;
RotaryEncoderReader reader(pinA, pinB);
void setup()
{
}
void loop()
{
}
I have an error that goes like this
In file included from Level.hpp:12,
from main.cpp:4:
Corridor.hpp: In method `void Game::Corridor::update()':
Corridor.hpp:41: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'
Corridor.hpp:42: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'
Corridor.hpp:43: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'
Corridor.hpp:44: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'
Corridor and Level are ...
// Corridor.hpp
#ifndef GAME_CORRIDOR_HPP
#define GAME_CORRIDOR_HPP
#include <Moot/Math.hpp>
//#include <Level.hpp>
#include <GameWindow.hpp>
namespace Game
{
class Level; // <-- LINE 13
class Corridor
{
static const unsigned int defaultLevelDepth = 800;
Moot::Math::Vector3D wp1, wp2, wp3, wp4;
Moot::Math::Vector2D sp1, sp2, sp3, sp4;
Level * p_level;
public:
Corridor(Moot::Math::Vector3D setFirstPoint, Moot::Math::Vector3D setSecondPoint)
{
wp1 = setFirstPoint;
wp2 = setSecondPoint;
wp3 = setFirstPoint;
wp3.z += defaultLevelDepth;
wp4 = setSecondPoint;
wp4.z += defaultLevelDepth;
}
void update() {
sp1 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp1); // <- LINE 41 etc.
sp2 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp2);
sp3 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp3);
sp4 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp4);
//p_level->getLevelCamera();
}
void draw()//const
{
Moot::Color tempColor;
windowInstance().graphics().drawQuad( sp1.x, sp1.y, tempColor,
sp2.x,sp2.y, tempColor,
sp3.x, sp3.y, tempColor,
sp4.x,sp4.y, tempColor, 1);
}
void setLevel(Level* setLevel) {
p_level = setLevel;
}
};
}
#endif
and
// Level.hpp
#ifndef GAME_LEVEL_HPP
#define GAME_LEVEL_HPP
#include <Moot/Forward.hpp>
#include <Moot/Window.hpp>
#include <Moot/Math.hpp>
#include <GameWindow.hpp>
#include <Camera.hpp>
#include <Corridor.hpp>
#include <Player.hpp>
#include <vector>
namespace Game
{
class Level
{
typedef Corridor* p_corridor;
typedef std::vector<p_corridor> CorridorList;
typedef CorridorList::reverse_iterator ReverseCorridorItter;
CorridorList m_map;
Camera m_camera;
Player m_player;
public:
Level()
{
m_player.setLevel(this);
// Lots of vertices being defined into m_map.
// Loop through and set camera
ReverseCorridorItter rit;
for(rit = m_map.rbegin(); rit != m_map.rend(); rit++)
(*rit)->setLevel(this);
}
~Level()
{
ReverseCorridorItter rit;
for(rit = m_map.rbegin(); rit != m_map.rend(); rit++)
delete (*rit);
m_map.clear();
}
void update()
{
// Temp delete when input and player are implimented.
if(pad[0].buttons & PAD_UP)
m_camera.updateTargetOffsets(0, -2);
if(pad[0].buttons & PAD_DOWN)
m_camera.updateTargetOffsets(0, 2);
if(pad[0].buttons & PAD_LEFT)
m_camera.updateTargetOffsets(-2, 0);
if(pad[0].buttons & PAD_RIGHT)
m_camera.updateTargetOffsets(2, 0);
m_player.update();
ReverseCorridorItter rit;
for (rit = m_map.rbegin(); rit != m_map.rend(); rit++)
(*rit)->update();
}
void draw() // const // EH!!! wtf ReverseIter isn't a member
{
m_player.draw();
ReverseCorridorItter rit;
for (rit = m_map.rbegin(); rit != m_map.rend(); rit++)
(*rit)->draw();
}
Camera& getLevelCamera() {
return m_camera;
}
};
}
#endif
The pointer is being set as far as I can tell, but when I try to access a function from Level, BOOM!
Thanks.
PS: The compiler is gcc 2.95.2 if that makes a difference.
EDIT
Updated with complete code.
You are #include-ing Level's complete declaration:
#include <Level.hpp>
...and then you try to forward-declare Level:
namespace Game
{
class Level;
Don't do this. Choose one or the other. (edit) Or at least put the forward-declaration before the #include-ion of the complete declaration. If all you're doing in game_corridor.hpp is setting pointers to a Level, then a forward declare should do fine. If however you need to call functions on Level from within the HPP file, then you'll need to #include the complete declaration.
EDIT2:
Based on your clarifying edit to your OP, you must #include the complete declaration of Level, and not try to use a forward declaration.
If you forward-declare Game::Level then don't #include it. In a not-so-related note, use #include "header.hpp", not #include <header.hpp>.
Edit as per your updates: Bring the definition of Game::Corridor::update() outside the header and into an implementation file. This way the compile need not know anything about Game::Level apart from the fact that it exists and it's a type.
The problem is that Corridor doesn't know what a Level is, because it can't really #include Level.hpp, because Level.hpp is what #included Corridor.hpp.
The underlying problem is that you're trying to #include a source file. The really underlying problem is that you're using #include when you haven't separated your code into source files and header files. Here's how to split it up. (I'm assuming you're familiar with compiling source files into object files, then linking them into executables.)
Corridor.hpp:
#ifndef GAME_CORRIDOR_HPP
#define GAME_CORRIDOR_HPP
#include <Moot/Math.hpp>
#include <Level.hpp>
namespace Game
{
class Level;
class Corridor
{
static const unsigned int defaultLevelDepth = 800;
Moot::Math::Vector3D wp1, wp2, wp3, wp4;
Moot::Math::Vector2D sp1, sp2, sp3, sp4;
Level * p_level;
public:
Corridor(Moot::Math::Vector3D setFirstPoint, Moot::Math::Vector3D setSecondPoint);
void update();
void draw();
void setLevel(Level* setLevel);
};
}
#endif
Corridor.cpp:
#include "Corridor.hpp"
namespace Game
{
Corridor::Corridor(Moot::Math::Vector3D setFirstPoint, Moot::Math::Vector3D setSecondPoint)
{
wp1 = setFirstPoint;
wp2 = setSecondPoint;
wp3 = setFirstPoint;
wp3.z += defaultLevelDepth;
wp4 = setSecondPoint;
wp4.z += defaultLevelDepth;
}
void Corridor::update()
{
sp1 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp1);
sp2 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp2);
sp3 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp3);
sp4 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp4);
}
// and so on
}