I want to compile a simple project with several additional classes in cpp. Unfortunately, when avr-g++ is called with avr-g++.exe -o stepper.elf src/add_functions.o src/ASF/common/services/hugemem/avr8/avr8_hugemem.o src/ASF/common/services/sleepmgr/xmega/sleepmgr.o src/ASF/common/services/spi/xmega_spi/spi_master.o src/ASF/xmega/drivers/dma/dma.o src/ASF/xmega/drivers/spi/spi.o src/gpio_control.o src/spi_control.o src/usart_control.o src/ASF/common/boards/user_board/init.o src/ASF/common/services/clock/xmega/sysclk.o src/ASF/common/services/ioport/xmega/ioport_compat.o src/ASF/common/services/serial/usart_serial.o src/ASF/xmega/drivers/cpu/ccp.o src/ASF/xmega/drivers/usart/usart.o src/main.o -Wl,-Map="stepper.map" -Wl,--start-group -Wl,-lm -Wl,--end-group -Wl,--gc-sections -mmcu=atxmega16a4 for the following code:
#include <asf.h>
#include <string.h>
#include "usart.h"
class usart_controller
{
//variables
public:
protected:
private:
static usart_rs232_options_t USART_options;
USART_t *usart;
//functions
public:
usart_controller(USART_t *usart, uint32_t baudrate, USART_CHSIZE_t charlength, USART_PMODE_t paritybyte, bool stopbit);
~usart_controller();
void send_data(uint32_t *data32, size_t data32_size);
uint8_t * rec_data();
protected:
private:
usart_controller( const usart_controller &c );
usart_controller& operator=( const usart_controller &c );
}; //usart_controller
#include "usart_control.h"
// default constructor
usart_controller::usart_controller(USART_t *usart, uint32_t baudrate, USART_CHSIZE_t charlength, USART_PMODE_t paritybyte, bool stopbit)
{
this->USART_options.baudrate = baudrate;
//this->USART_SERIAL_OPTIONS.charlength = charlength;
//this->USART_SERIAL_OPTIONS.paritytype = paritybyte;
//this->USART_SERIAL_OPTIONS.stopbits = stopbit;
this->usart = usart;
//usart_init_rs232(usart, &(this->USART_SERIAL_OPTIONS));
} //usart_controller
// default destructor
usart_controller::~usart_controller()
{
} //~usart_controller
void usart_controller::send_data(uint32_t * data32, size_t data32_size)
{
size_t data_size = 4 * data32_size;
uint8_t *data = new uint8_t[data32_size * 4];
for(unsigned int i = 0; i < data32_size; i++)
{
for(int j = 0; j < 4; j++)
{
data[i*j+j] = (data32[i] << (j*8));
}
}
usart_serial_write_packet(this->usart, data, data_size * sizeof(uint8_t));
delete[] data;
}
uint8_t * usart_controller::rec_data()
{
uint8_t * data = new uint8_t[32];
usart_serial_read_packet(this->usart, data, 32*sizeof(uint8_t));
return data;
}
I get the error " error: undefined reference to usart_controller::USART_options'" for the commandthis->USART_options.baudrate = baudrate;`. When I compile it alone, everything is going fine, and I get a valid object file. When trying to link it afterwards I get the error shown above. Why? Did I miss something? I am already linking everything I need.
In c++, it's not enough to declare a static data member in a class. It also has to be defined somewhere to allocate memory for it. If you add
usart_rs232_options_t usart_controller::USART_options;
somewhere in your source file (e.g. right after the class definition), it will be linked just fine :)
PS: Atmel? Have fun and be careful with that little devil! :)
Related
I am fairly new to c++, I was making a encryptor to imrpove my c++, at first I kept my Cryptographer class in cryptographer.hpp and then added function body in cryptographer.cpp and then included cryptographer.hpp in main.cpp it gave me a compiler error, so I just pasted the code in main.cpp like this
#include <iostream>
#include <map>
class Cryptographer{
public:
int n_factor;
std::string text;
Cryptographer(std::string user_arg, int user_n_factor);
struct cryptographer
{
std::string encrypted_text;
std::string generated_key="";
};
cryptographer crypted_text;
void generate_key();
void encrypt();
void decrypt();
std::string get_key();
std::string get_text();
};
using key_map = std::map<char, std::string[5]>;
void Cryptographer::generate_key(){
for (int _ = 0; _ < 5; _++){
crypted_text.generated_key += rand() % 26 + 65;
}
}
void Cryptographer::encrypt(){
generate_key();
key_map keyHashMap;
for (auto key_letter: crypted_text.generated_key){
int key_letter_int = (int) key_letter;
std::string key_letter_arr[5];
int memory_number = key_letter_int;
for (int index=0; index < 5; index++){
if (memory_number+n_factor > 91){
memory_number = 65;
}else{
key_letter_arr[5] = std::string(1, char (memory_number + n_factor));
memory_number += n_factor;
}
}
keyHashMap.emplace(key_letter, key_letter_arr);
}
for(int index=0; index<text.size(); index++){
int key = index %4;
int key_patter = rand()% 4;
int checking_index = 0;
for (auto &elem: keyHashMap){
if (checking_index == key){
std::cout << elem.second[1];
}
}
}
crypted_text.encrypted_text = "test";
}
Cryptographer::Cryptographer(std::string user_arg, int user_n_factor):
text(user_arg), n_factor(user_n_factor)
{}
int main(){
Cryptographer crypter("hello guys", 3);
crypter.encrypt();
std::cout << crypter.get_text();
return 0;
}
and ran this in my terminal
g++ main.cpp -o test
and it popped this large error
https://hastebin.com/cibeyanoro.cpp
I am on ubuntu 20.04, I also tried removing and reinstalling latest version of g++ but the same error pops up.
g++ error in compiling while using std::string[5] as a type in std::map<>
Arrays cannot be stored as elements of std::map. You can store classes though, and arrays can be members of a class. The standard library provides a template for such array wrapper. It's called std::array. You can use that as the element of the map instead.
Sidenote: std::map isn't the only standard container with such limitation. std::array is the only standard container that can itself contain arrays as elements.
I am new to c++.
It looks like member variable _scheduleSize gets value kind of "integer_half_max" without any reason. Could someone please explain me why is this happening?
Invocation
leds.addSchedulePoint(new ScheduledLedPoint(ScheduleTime(9), 0));
of method:
void ScheduledLeds::addSchedulePoint(ScheduledLedPoint *schedulePoint) {
Serial.print("_scheduleSize:");
Serial.println(_scheduleSize);
_schedule[_scheduleSize++] = schedulePoint;
Serial.print("_scheduleSize:");
Serial.println(_scheduleSize);
for (size_t i = 0; i < _scheduleSize; i++) {
Serial.println(_schedule[i]->getLevel());
}
}
results in such console output :
_scheduleSize:0
_scheduleSize:1073680860
0
Exception (28):
epc1=0x40206514 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000010 depc=0x00000000
Below you can see entire class:
class ScheduledLeds {
public:
ScheduledLeds(int pin);
void addSchedulePoint(ScheduledLedPoint *schedulePoint);
void process(ScheduleTime currentTime);
void freezeLedLevel(int targetLevel, int minutes);
int _pin;
private:
ScheduledLedPoint *_schedule[];
int _scheduleSize;
int _count;
int _size;
long _unfreezeTime;
int _lastLevel;
ScheduleTime _lastTime;
void setTransitionalLightLevel(ScheduleTime now, ScheduledLedPoint nextPoint);
void setLightLevel(int targetLevel);
};
ScheduledLeds::ScheduledLeds(int pin) {
pinMode(pin, OUTPUT);
_pin = pin;
_scheduleSize = 0;
_size = 10;
_unfreezeTime = millis();
ScheduledLedPoint *_schedule[_size];
}
void ScheduledLeds::addSchedulePoint(ScheduledLedPoint *schedulePoint) {
Serial.print("_scheduleSize:");
Serial.println(_scheduleSize);
_schedule[_scheduleSize++] = schedulePoint;
Serial.print("_scheduleSize:");
Serial.println(_scheduleSize);
for (size_t i = 0; i < _scheduleSize; i++) {
Serial.println(_schedule[i]->getLevel());
}
}
ScheduledLedPoint *_schedule[]; is not valid C++ and shouldn't compile. Some compilers accept it as an extension - but even there, it's an array of zero size; _schedule[x] exhibits undefined behavior for any value of x.
When you write ScheduledLedPoint *_schedule[_size] in the constructor, that doesn't affect the data member named _schedule, as you seem to believe. Instead, it creates and immediately destroys a local variable that also happens to be named _schedule; this has exactly zero net effect.
For an array-like data structure of variable size, use std::vector.
because you have syntax error including this recursive function
I have currently a problem with the following C++ class, which holds the model logic of a cube. The constructor creates a dynamic 2d char array with the following content:
[ [0,0,0,0,0,0],
[1,1,1,1,1,1],
[2,2,2,2,2,2],
[3,3,3,3,3,3],
[4,4,4,4,4,4],
[5,5,5,5,5,5] ].
CubeModel.h
#ifndef CUBEMODEL_H_INCLUDED
#define CUBEMODEL_H_INCLUDED
#include <iostream>
class CubeModel
{
private:
const unsigned short m_faces;
const unsigned short m_fields;
char **m_cube_base_pointer;
public:
CubeModel(const unsigned short faces, const unsigned short fields);
~CubeModel();
void output();
};
#endif // CUBEMODEL_H_INCLUDED
CubeModel.cpp
#include "CubeModel.h"
CubeModel::CubeModel(const unsigned short faces, const unsigned short fields): m_faces(faces), m_fields(fields) {
m_cube_base_pointer = new char*[m_faces];
for (unsigned int i = 0; i < m_faces; ++i) {
m_cube_base_pointer[i] = new char[m_fields * m_fields];
memset(m_cube_base_pointer[i], i, sizeof m_cube_base_pointer[i]);
}
}
CubeModel::~CubeModel() {
for (unsigned int i = 0; i < m_faces; ++i) {
std::cout << (int) m_cube_base_pointer[i][0];
delete [] m_cube_base_pointer[i];
}
delete [] m_cube_base_pointer;
}
/*
Console output of the cube model
*/
void CubeModel::output() {
for (unsigned int i = 0; i < m_faces; ++i) {
for (unsigned int j = 0; j < m_fields * m_fields; ++j) {
std::cout << (int) m_cube_base_pointer[i][j] << std::endl; // output the model
}
}
}
main.cpp
#include <iostream>
#include "CubeModel.h"
using namespace std;
int main() {
CubeModel cube = CubeModel(6, 3);
cube.output();
system("PAUSE");
return 0;
}
When I create a CubeModel object in the main function and call the output method, I got the following error message in Visual Studio:
Exception raised at 0x00FC1DC8 in Cube.exe: 0xC0000005: Access violation at reading a position 0x00000000.
The exception is raised inside the output() method in CubeModel.
What I'm doing wrong here?
The third argument of memset is the number of bytes you want to set.
However
sizeof m_cube_base_pointer[i]
will give you the size of the pointer, not the size of the dynamic array you just allocated. So in order to get the right number of bytes you want to set, you should do
sizeof(char) * m_fields * m_fields
instead. And your memset call should become this:
memset(m_cube_base_pointer[i], i, sizeof(char) * m_fields * m_fields);
//this is my main Method ,this was an experiment to understand shared pointer usage
#include <iostream>
#include "shared_ptrtestA.h"
int main(int argc, const char * argv[]) {
// declare a shared pointer to the class
sharedptr_testA* A = new sharedptr_testA(5);
//class has a vector , push back a new instance into the vector
A->mvect.push_back(sharedptr_testA::Aptr(new sharedptr_testA::testA(
sharedptr_testA::sharedptr_testB::Create(1) , sharedptr_testA::sharedptr_testC::Create(1)
)));
//class has a vector , push back a new instance into the vector
A->mvect.push_back(sharedptr_testA::Aptr(new sharedptr_testA::testA(
sharedptr_testA::sharedptr_testB::Create(2),sharedptr_testA::sharedptr_testC::Create(2)
)));
//iterate the vector populated above
for(std::vector<sharedptr_testA::Aptr>::iterator it = A->mvect.begin() ;
it!= A->mvect.end() ; it++)
{
// get members from the vector iterator
sharedptr_testA:: sharedptr_testB::Bptr B = (*it)->mb;
sharedptr_testA:: sharedptr_testC::Cptr C = (*it)->mc;
// print contents of members
for(int i = 0 ; i < B->m_size ; i++)
{
std::cout<<B->bytes[i]<<'\t';
}
std::cout <<std::endl;
for(int i = 0 ; i < C->m_size ; i++)
{
std::cout<<C->bytes[i]<<'\t';
}
std::cout <<std::endl;
}
}
//this was the main method above and the expected output was
B
C
BB
CC
The structure of the classes used are
//Header File
#ifndef shared_ptrtest_shared_ptrtestA_h
#define shared_ptrtest_shared_ptrtestA_h
#include <memory>
#include <functional>
#include <vector>
class sharedptr_testA
{
public:
// constructor and destructor
sharedptr_testA(int vsize);
~sharedptr_testA();
// an internal class member defined
class sharedptr_testB
{
public:
typedef std::shared_ptr<sharedptr_testB> Bptr;
//static create method
static Bptr Create(int msize)
{
return Bptr(new sharedptr_testB(msize));
}
//members
int m_size;
char *bytes;
//private contructor
private:
sharedptr_testB(int size)
{
m_size = size;
bytes = new char[size];
for(int i = 0 ; i < size ; i++)
bytes[size]= 'B';
}
};
//class c has same structure as class B above
class sharedptr_testC
{
public:
typedef std::shared_ptr<sharedptr_testC> Cptr;
static Cptr Create(int msize)
{
return Cptr(new sharedptr_testC(msize));
}
int m_size;
char *bytes;
private:
sharedptr_testC(int size)
{
m_size = size;
bytes = new char[size];
for(int i = 0 ; i < size ; i++)
bytes[size]= 'C';
}
};
// struct containing shared pointers to classes defined above
struct testA
{
testA(sharedptr_testB::Bptr B, sharedptr_testC::Cptr C)
{
mb = B;
mc = C;
}
sharedptr_testB::Bptr mb;
sharedptr_testC::Cptr mc;
};
typedef std::shared_ptr<testA> Aptr;
std::vector<Aptr> mvect;
};
#endif
//The short cpp file for the above class contains only constructor and destructor
#include "shared_ptrtestA.h"
sharedptr_testA::sharedptr_testA(int vsize)
:mvect(vsize)
{
}
sharedptr_testA::~sharedptr_testA()
{
}
What is wrong in the above code ? I wrote this to understand shared pointer usage
You have two bugs in your program:
The loops in constructors of sharedptr_testB and sharedptr_testC use size instead of i for indexing. It should be:
sharedptr_testB(int size)
{
m_size = size;
bytes = new char[size];
for(int i = 0 ; i < size ; i++)
bytes[i]= 'B';
}
(DTTO) for sharedptr_testC)
You start with a vector of size 5, which means it stores five null pointers. Then you append two elements to it (size 7, five nulls + two valid pointers). The you iterate over it, dereferencing each pointer. This of course crashes, since there are nulls at the beginning. Simply initialise the vector as empty.
sharedptr_testA* A = new sharedptr_testA(0);
With these two fixes, the code works.
Side notes 1 (C++):
The code is next to impossible to read. I strongly suggest you use a better naming scheme.
sharedptr_testB and sharedptr_testC leak memory. I understand it's just a learning excercise, I'd just like to point it out. You'd be better off with std::vector<char> in them instead of char*.
Side notes 2 (Stack Overflow):
If you have a crashing program, you should generally try to debug it yourself before asking an SO question. Stepping through the program through a debugger would easily have uncovered both the issues.
I am trying to write this C++ function in which I am trying to set each Sequence in the array of Sequences, however when I follow the code on debug I notice that the array is not changing. In particular:
compressed.data[compressedDataCounter].c = pic.data[i];
compressed.data[compressedDataCounter].times = counter+1;
don't seem to add any new variables to the array, just override the first one.
I am thinking that the root of the problem is the declaration:
CompressedPic compressed;
compressed.data = new Sequence[pic.height * pic.width];
This is the portion of the code:
struct Sequence
{
char c;
int times;
};
struct CompressedPic
{
int height;
int width;
Sequence* data;
};
struct Picture
{
int height;
int width;
char* data;
};
CompressedPic compressThePicture(Picture pic) {
CompressedPic compressed;
compressed.data = new Sequence[pic.height * pic.width];
compressed.height = pic.height;
compressed.width = pic.width;
int compressedDataCounter=0;
for(int i=0; i<(pic.height * pic.width)-1; i++)
{
int counter = 0;
while(pic.data[i] == pic.data[i+1])
{
i++;
counter++;
}
compressed.data[compressedDataCounter].c = pic.data[i];
compressed.data[compressedDataCounter].times = counter+1;
compressedDataCounter++;
}
compressed.data[compressedDataCounter].times = -1;
return compressed;
}
It would be great if someone could figure out why this is happening.
You might want to change:
compressed.data[compressedDataCounter].c = counter+1;
to:
compressed.data[compressedDataCounter].times = counter+1;
So you can change the .times member otherwise you will be overriding your .c member. Right now you are setting .c to 'a' for example. Then you set .c to 103 (counter+1). Which is an int and likely with your archetecture the high bytes are aligning with .c and setting it to 0 as well.
So .c is getting 0'd and .times is never set