Почему определение длины буфера буфера приводит к тому, что член функции этого класса теряет значение переменной-члена указателя функции?

Я работаю с GNU AVR GCC версии 5.4.0 и Atmelstudio 7.0.2397, и у меня есть следующая проблема.


описание проблемы

На следующем изображении вы можете видеть, что до строки 13 программа сохранила адрес функции usart_send в переменной transmitter, которая является членом SimpleClass объекта sc.

введите здесь описание изображения

Прототип функции transmitter void (*transmitter)(uint8_t * txbuff, uint8_t len);, а определение прототипа функции usart_sendvoid usart_send(uint8_t *, uint8_t);.

Теперь, когда я вхожу в функцию foo, обратите внимание, что внутри функции-члена объекта класса адрес transmitter теперь равен 0.

введите здесь описание изображения

Точно так же внутри функции flush ее значение по-прежнему равно 0. Поэтому я не могу вызвать нужную функцию. И это то, что показывает разборка, и мой 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. Это определение определения вызывает указанную выше проблему. Если я удалю эти две строки, этот код будет работать нормально.


Вопрос

Таким образом, вы можете видеть, что определение длины буфера для буфера, который находится внутри класса, приводит к тому, что его функция-член теряет значение указателя функции класса (который является переменной-членом). И я хочу знать, почему?


Код

Здесь много неиспользуемых функций, и это потому, что я изолировал ошибку (если это ошибка!) из моего проекта.

main.cpp

#include "IncFile1.h"

SimpleClass sc;

int main(void)
{
    
    usart_init();
    timer0_init();
    
    sc.transmitter = &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);

Простой класс.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] != '\0';i++){
            while(!(UCSR0A & (1<<UDRE0)));
            UDR0 = c[i];
        }
        while(!(UCSR0A & (1<<UDRE0)));
        UDR0 = 0x0a;
        while(!(UCSR0A & (1<<UDRE0)));
        UDR0 = 0x0d;
    }
    
    void usart_send(uint8_t *buff, uint8_t len){
        for(uint8_t i = 0; i < len; i++){
            while(!(UCSR0A & (1<<UDRE0)));
            UDR0 = buff[i];
        }
    }
    
    void usart_send_ln(uint32_t num){
        for(uint8_t i =0;i < 4; i++){
            while(!(UCSR0A & (1<<UDRE0)));
            UDR0 = num >> (8*(3-i));
        }
    }

Правки


person Sanmveg saini    schedule 21.09.2020    source источник
comment
У вас есть два разных определения SimpleClass. Это нарушает правило одного определения, и ваша программа ведет себя неопределенно.   -  person molbdnilo    schedule 21.09.2020


Ответы (1)


Вы нарушаете правило одного определения: компоновка программы C++, в которой один и тот же класс определен дважды, и эти определения не идентичны, является поведением undefined. Компилятор/компоновщик не обязан проверять или сообщать об этих ошибках.

Вы делаете именно это:

  • CPPFile1.cpp включает IncFile1.h, что создает SimpleClass определение с buffers[50],
  • SimpleClass.cpp включает SimpleClass.h с buffers[30].
person Quimby    schedule 21.09.2020
comment
@Sanmvegsaini Как насчет тех двух единиц перевода, которые я упомянул? Имеют ли они одинаковую длину? Суть в том, что вы должны убедиться, что все эти определения одинаковы. Нет смысла определять длину как переопределяемый макрос, используйте const static, constexpr, если можете. - person Quimby; 21.09.2020
comment
Это отличный совет! Я сделал некоторые изменения, и я получил ошибку. Спасибо. - person Sanmveg saini; 21.09.2020