为什么定义缓冲区的缓冲区长度会导致 class 的函数成员丢失函数指针成员变量的值?
Why defining buffer length of a buffer leads to that class's function member to loose the value of a function pointer member variable?
我正在使用 GNU AVR GCC 5.4.0 版和 Atmelstudio 7.0.2397,我遇到了以下问题。
问题描述
在下图中,您可以看到直到第 13 行,程序已将函数 usart_send
的地址存储到作为 SimpleClass
对象成员的 transmitter
变量中sc
.
transmitter
函数的原型是void (*transmitter)(uint8_t * txbuff, uint8_t len);
,usart_send
函数原型定义是void usart_send(uint8_t *, uint8_t);
.
现在,当我进入 foo
函数时,请注意在 class 对象的成员函数内部时,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();
};
注意使用 define
定义了 txBuffer
和 rxBuffer
的长度。在 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 的这个定义导致了上面的问题。如果我删除这两行,这段代码工作正常。
问题
所以你可以看到,通过为 class 中的缓冲区定义缓冲区长度,导致其成员函数丢失 class 的函数指针(这是一个成员变量)。我想知道为什么?
代码
这里有许多未使用的函数,这是因为我正在从我的项目中隔离错误(如果它是错误!)。
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);
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] != '[=17=]';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));
}
}
编辑
您违反了单一定义规则 - 链接 C++ 程序,其中相同的 class 定义了两次 并且这些定义不相同 是未定义的行为。 compiler/linker 不需要检查或报告这些错误。
您正在这样做:
CPPFile1.cpp
包含 IncFile1.h
,它使用 buffers[50]
、 创建 SimpleClass
定义
SimpleClass.cpp
包括 SimpleClass.h
和 buffers[30]
。
我正在使用 GNU AVR GCC 5.4.0 版和 Atmelstudio 7.0.2397,我遇到了以下问题。
问题描述
在下图中,您可以看到直到第 13 行,程序已将函数 usart_send
的地址存储到作为 SimpleClass
对象成员的 transmitter
变量中sc
.
transmitter
函数的原型是void (*transmitter)(uint8_t * txbuff, uint8_t len);
,usart_send
函数原型定义是void usart_send(uint8_t *, uint8_t);
.
现在,当我进入 foo
函数时,请注意在 class 对象的成员函数内部时,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();
};
注意使用 define
定义了 txBuffer
和 rxBuffer
的长度。在 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 的这个定义导致了上面的问题。如果我删除这两行,这段代码工作正常。
问题
所以你可以看到,通过为 class 中的缓冲区定义缓冲区长度,导致其成员函数丢失 class 的函数指针(这是一个成员变量)。我想知道为什么?
代码
这里有许多未使用的函数,这是因为我正在从我的项目中隔离错误(如果它是错误!)。
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);
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] != '[=17=]';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));
}
}
编辑
您违反了单一定义规则 - 链接 C++ 程序,其中相同的 class 定义了两次 并且这些定义不相同 是未定义的行为。 compiler/linker 不需要检查或报告这些错误。
您正在这样做:
CPPFile1.cpp
包含IncFile1.h
,它使用buffers[50]
、 创建 SimpleClass.cpp
包括SimpleClass.h
和buffers[30]
。
SimpleClass
定义