gpt4 book ai didi

C:使用头文件中的函数最小化代码重复

转载 作者:太空狗 更新时间:2023-10-29 16:06:52 27 4
gpt4 key购买 nike

这是一个有点奇怪的用例,因此很难搜索现有的讨论。我正在为嵌入式系统(使用 XC16 编译器的 Microchip PIC24)编程,目前正在跨 3 个独立的 UART channel (每个 UART 将从主数据表中获取数据)实现相同的通信协议(protocol)。

我开始编写项目的方式是让每个 UART 由一个单独的模块处理,有很多代码重复,按照以下伪代码行:

UART1.c:

static unsigned char buffer[128];
static unsigned char pointer = 0;
static unsigned char packet_received = 0;

void interrupt UART1Receive (void) {
buffer[pointer++] = UART1RX_REG;
if (end of packet condition) packet_received = 1;
}

void processUART1(void) { // This is called regularly from main loop
if (packet_received) {
// Process packet
}
}

UART2.c:

static unsigned char buffer[128];
static unsigned char pointer = 0;
static unsigned char packet_received = 0;

void interrupt UART2Receive (void) {
buffer[pointer++] = UART2RX_REG;
if (end of packet condition) packet_received = 1;
}

void processUART2(void) { // This is called regularly from main loop
if (packet_received) {
// Process packet
}
}

虽然上面的内容简洁且运行良好,但实际上通信协议(protocol)本身相当复杂,因此将其复制三次(只是更改对 UART 寄存器的引用)增加了引入错误的机会。拥有一个单一的函数并向它传递指针不是一种选择,因为这会对速度产生太大的影响。代码需要在每个 UART 的内存中进行物理复制。

我想了很多,尽管知道永远不要将函数放在头文件中的规则,但还是决定尝试一个包含重复代码的特定头文件,引用为#defined 值:

协议(protocol).h:

// UART_RECEIVE_NAME and UART_RX_REG are just macros to be defined 
// in calling file
void interrupt UART_RECEIVE_NAME (void) {
buffer[pointer++] = UART_RX_REG;
if (end of packet condition) packet_received = 1;
}

UART1.c:

static unsigned char buffer[128];
static unsigned char pointer = 0;
static unsigned char packet_received = 0;

#define UART_RECEIVE_NAME UART1Receive
#define UART_RX_REG UART1RX_REG

#include "protocol.h"

void processUART1(void) { // This is called regularly from main loop
if (packet_received) {
// Process packet
}
}

UART2.c:

static unsigned char buffer[128];
static unsigned char pointer = 0;
static unsigned char packet_received = 0;

#define UART_RECEIVE_NAME UART2Receive
#define UART_RX_REG UART2RX_REG

#include "protocol.h"

void processUART2(void) { // This is called regularly from main loop
if (packet_received) {
// Process packet
}
}

当代码编译没有任何错误时,我感到有些惊讶!不过它似乎确实有效,编译后 MPLAB X 甚至可以计算出所有符号引用,这样 UART1.c 和 UART2.c 中的每个宏引用都不会被识别为不可解析的标识符。然后我意识到我可能应该将 protocol.h 文件重命名为 protocol.c(并相应地更新 #includes),但这实际上没什么大不了的。

只有一个缺点:IDE 在模拟或调试时单步执行 protocol.h 中包含的代码时不知道要做什么。它只是在代码执行时停留在调用指令处,因此调试会稍微困难一些。

那么这个解决方案有多难? C神会不会因为我考虑这个而打我?有没有我忽略的更好的选择?

最佳答案

另一种方法是定义一个包含代码主体的函数宏。一些 token 粘贴操作符可以自动生成所需的符号名称。多行宏可以通过在除最后一行以外的所有末尾使用 \ 来生成。

#define UART_RECEIVE(n) \
void interrupt UART##n##Receive (void) { \
buffer[pointer++] = UART##n##RX_REG; \
if (end of packet condition) packet_received = 1; \
}

UART_RECEIVE(1)
UART_RECEIVE(2)

关于C:使用头文件中的函数最小化代码重复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26153574/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com