#c #avr-gcc #atmelstudio
#c #avr-gcc #atmelstudio
Вопрос:
Я работаю с GNU AVR GCC версии 5.4.0 и Atmelstudio 7.0.2397, и у меня следующая проблема.
Описание проблемы
На следующем изображении вы можете видеть, что вплоть до строки 13 программа сохранила адрес функции usart_send
в transmitter
переменной, которая является членом SimpleClass
object sc
.
Прототипом transmitter
функции является void (*transmitter)(uint8_t * txbuff, uint8_t len);
usart_send
определение прототипа функции void usart_send(uint8_t *, uint8_t);
.
Теперь, когда я перехожу в foo
функцию, обратите внимание, что внутри функции-члена объекта класса адрес transmitter
теперь равен 0.
Аналогично внутри функции flush
ее значение по-прежнему равно 0. Поэтому я не могу вызвать нужную функцию. И это то, что показывает disassembly, как и мой MCU.
Причина этой проблемы
Итак, у меня есть следующий код для SimpleClass.h
#pragma once
typedef unsigned char uint8_t;
#ifndef rxBufferLen
#define rxBufferLen 30
#endif
#ifndef txBufferLen
#define txBufferLen 30
#endif
class SimpleClass{
uint8_t rxbuffer[rxBufferLen]; ///< receiver buffer
uint8_t txBuffer[txBufferLen]; ///< transmitter buffer
uint8_t rxbuff_index, ///< rxbuffer index. Indicates where to put new data
txbuff_index; ///< txBuffer index. Indicates where to put new data
public:
void (*transmitter)(uint8_t * txbuff, uint8_t len);
void pushtx(uint8_t byte);
void pushrx(uint8_t byte);
void flush();
void foo();
};
Обратите внимание, что длина txBuffer
и rxBuffer
определяется с помощью define
. И у incfile1.h
меня есть следующий код.
#pragma once
#define rxBufferLen 50
#define txBufferLen 50
#include <avr/io.h>
#include "simpleClass.h"
#define TIMER0_CLOCK_PRESCALAR (3)
#define TIMER0_CLOCK_COUNT (0xff - 50)
void usart_init();
void timer0_init();
void serial_send_ln(const char *);
void usart_send(uint8_t *, uint8_t);
void usart_send_ln(uint32_t num);
Здесь я переопределил rxBufferLen
и txBufferLen
. Это определение define вызывает вышеупомянутую проблему. Если я удалю эти две строки, этот код будет работать нормально.
Вопрос
Итак, вы можете видеть, что определение длины буфера для буфера, который находится внутри класса, приводит к тому, что его функция-член теряет значение указателя функции класса (который является переменной-членом). И я хочу знать, почему?
Code
Here are many un used functions and this is because I was isolating bug(if it is a bug!) from my project.
main.cpp
#include "IncFile1.h"
SimpleClass sc;
int main(void)
{
usart_init();
timer0_init();
sc.transmitter = amp;usart_send;
sc.foo();
while (1)
{
}
}
IncFile.h
#pragma once
#define rxBufferLen 50
#define txBufferLen 50
#include <avr/io.h>
#include "simpleClass.h"
#define TIMER0_CLOCK_PRESCALAR (3)
#define TIMER0_CLOCK_COUNT (0xff - 50)
void usart_init();
void timer0_init();
void serial_send_ln(const char *);
void usart_send(uint8_t *, uint8_t);
void usart_send_ln(uint32_t num);
SimpleClass.h
#pragma once
typedef unsigned char uint8_t;
#ifndef rxBufferLen
#define rxBufferLen 30
#endif
#ifndef txBufferLen
#define txBufferLen 30
#endif
class SimpleClass{
uint8_t rxbuffer[rxBufferLen]; ///< receiver buffer
uint8_t txBuffer[txBufferLen]; ///< transmitter buffer
uint8_t rxbuff_index, ///< rxbuffer index. Indicates where to put new data
txbuff_index; ///< txBuffer index. Indicates where to put new data
public:
void (*transmitter)(uint8_t * txbuff, uint8_t len);
void pushtx(uint8_t byte);
void pushrx(uint8_t byte);
void flush();
void foo();
};
SimpleClass.cpp
#include "simpleClass.h"
void SimpleClass::flush(){
transmitter(txBuffer, txbuff_index);
}
void SimpleClass::pushtx(uint8_t byte){
txBuffer[txbuff_index ] = byte;
}
void SimpleClass::pushrx(uint8_t byte){
rxbuffer[rxbuff_index ] = byte;
}
void SimpleClass::foo(){
uint8_t dv = 0;
dv ;
pushtx(0x01);
pushtx(0x02);
pushtx(0x03);
pushtx(0x04);
pushtx(0x05);
flush();
}
CPPFile1.cpp
#include "IncFile1.h"
void usart_init(){
unsigned int ubrr = 51;
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/*Enable receiver and transmitter */
UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, stop bit */
UCSR0C = (3<<UCSZ00);
}
void timer0_init(){
TCCR0B = TIMER0_CLOCK_PRESCALAR;
TIMSK0 = 1; // enable timer overflow interrupt
TCNT0 = TIMER0_CLOCK_COUNT;
}
void serial_send(const char * c){
for(uint8_t i=0 ; c[i] != '';i ){
while(!(UCSR0A amp; (1<<UDRE0)));
UDR0 = c[i];
}
while(!(UCSR0A amp; (1<<UDRE0)));
UDR0 = 0x0a;
while(!(UCSR0A amp; (1<<UDRE0)));
UDR0 = 0x0d;
}
void usart_send(uint8_t *buff, uint8_t len){
for(uint8_t i = 0; i < len; i ){
while(!(UCSR0A amp; (1<<UDRE0)));
UDR0 = buff[i];
}
}
void usart_send_ln(uint32_t num){
for(uint8_t i =0;i < 4; i ){
while(!(UCSR0A amp; (1<<UDRE0)));
UDR0 = num >> (8*(3-i));
}
}
Правки
Комментарии:
1. У вас есть два разных определения
SimpleClass
. Это нарушает правило единого определения, и ваша программа имеет неопределенное поведение.
Ответ №1:
Вы нарушаете правило единого определения — связывание программы C , в которой один и тот же класс определен дважды, и эти определения не идентичны, является неопределенным поведением. Компилятор / компоновщик не обязан проверять или сообщать об этих ошибках.
Вы делаете именно это:
CPPFile1.cpp
включаетIncFile1.h
в себя, который создаетSimpleClass
определение сbuffers[50]
,SimpleClass.cpp
включаетSimpleClass.h
withbuffers[30]
.
Комментарии:
1. @Sanmvegsaini Как насчет тех двух единиц перевода, о которых я упоминал? Имеют ли они одинаковую длину? Суть в том, что вы должны убедиться, что все эти определения одинаковы. Нет смысла определять длину как переопределяемый макрос, используйте
const static
,constexpr
если можете.2. Это отличный совет! Я внес некоторые изменения и получил ошибку. Спасибо.