C或C++;选择代码块的预处理器 我试图为一个嵌入式系统编写一个生产测试软件,在那里我可以编写一个测试脚本(理想的是C++代码),其中部分在主机上执行,部分在DUT(被测试设备)上。通信是通过串行端口进行的

C或C++;选择代码块的预处理器 我试图为一个嵌入式系统编写一个生产测试软件,在那里我可以编写一个测试脚本(理想的是C++代码),其中部分在主机上执行,部分在DUT(被测试设备)上。通信是通过串行端口进行的,c++,c-preprocessor,conditional-compilation,C++,C Preprocessor,Conditional Compilation,这里的一个重要目标是减少嵌入式端的代码大小,而不降低测试输出的可读性。所以我的0级目标,你可以说是热身练习,就是能够写出这样的东西: //TestScript.cpp START_TESTS() ... const unsigned pot1res = testPotentiometer(pot1); TEST_PRINT("Potentiometer 1 test result %u", pot1res); const unsigned pot2res = test

这里的一个重要目标是减少嵌入式端的代码大小,而不降低测试输出的可读性。所以我的0级目标,你可以说是热身练习,就是能够写出这样的东西:

//TestScript.cpp
START_TESTS() 
...
 const unsigned pot1res = testPotentiometer(pot1);
 TEST_PRINT("Potentiometer 1 test result %u", pot1res);
 const unsigned pot2res = testPotentiometer(pot2);
 TEST_PRINT("Potentiometer 2 test result %u", pot2res);
...
END_TESTS()
它将通过预处理器的欺骗和嵌入式端的选择性编译来编译

 const unsigned pot1res = testPotentiometer(pot1);
 write_uart(123); //Unique id, perhaps from __COUNTER__
 write_uart(pot1res);
 const unsigned pot2res = testPotentiometer(pot2);
 write_uart(124); //Unique id, perhaps from __COUNTER__
 write_uart(pot2res);
主持人呢?

std::array gTestStrings = {
        ... other strings ....
    TestString{123, "Potentiometer 1 test result %u", unsigned_tag},
    TestString{124, "Potentiometer 2 test result %u", unsigned_tag},
         ... more strings ....
};
后者的目的当然是,主机软件只需侦听UART以获取唯一id,然后从
gTestStrings
中查找所需参数,接收它们,并将消息打印到其测试日志中。请注意,字符串已从嵌入端完全消失

这里的嵌入端当然很简单,只需以明显的方式定义
TEST\u PRINT
宏,支持varargs等应该不会太难。但是,不清楚如何定义主机端,因为宏之间的代码必须完全消失。我很确定我可以用一些模板等正确地获取
unsigned_标记

标准C++17是值得赞赏的,但如果需要,GCC/Clang细节是允许的,预处理器显然将在这方面发挥重要作用。当然,宏的语法也可以在必要时进行调整。

基于“使用模板对不同类型执行相同的操作””您可以简单地定义一个模板化类或方法,该类或方法根据嵌入上下文或主机上下文调用不同的实现


伪代码示例:

#include <sstream>
#include <string>

class Mock
{
protected:
    // TODO : output values array / map - by - testID

public:
    unsigned readPot(int const testID)
    {
        // TODO : return value from the values array/map
    }

};

class ActualDevice
{
public:
    unsigned readPot(int const testID)
    {
        // TODO : write/read the device
    }

};

//DEVICE_IMPL must implement a method with this signature:
//unsigned readPot(int const testID)
template<typename DEVICE_IMPL>
void runTests()
{
    DEVICE_IMPL device;
    std::string testOutput;
    
    //TODO : substitute with for-loop to run all tests
    int testID = 1;
    {
        unsigned output = device.readPot(testID);
        std::stringstream accum;
        accum << "Test " << testID << " output = " << (int)output << std::endl;
        testOutput = accum.str();
        // TODO : do something with testOutput
    }
}

void testHost ()
{
    runTests<Mock>();
}


void testDevice()
{
    runTests<ActualDevice>();
}
#包括
#包括
课堂模拟
{
受保护的:
//TODO:输出值数组/map-by-testID
公众:
无符号读取器(int const testID)
{
//TODO:从值数组/映射返回值
}
};
类实际设备
{
公众:
无符号读取器(int const testID)
{
//TODO:写入/读取设备
}
};
//设备\u IMPL必须实现具有此签名的方法:
//无符号读取器(int const testID)
模板
void运行测试()
{
装置\植入装置;
std::字符串testOutput;
//TODO:替换为for循环以运行所有测试
int-testID=1;
{
无符号输出=device.readPot(testID);
标准::stringstream accum;
累积

我并不特别喜欢这种设计——对我来说似乎不够灵活。但这样的代码可以作为模板,让您编写更好的东西。我在
测试
宏中添加了表达式,这样就可以在主机端删除它,并在设备端使用它。

另一个选项可以是X宏:

盆栽试验

嵌入式.c

host.cpp


我不明白,您如何删除
const unsigned pot2res=testpotential(pot2);
行?什么是
unsigned_标记
?unsigned_标记(这里可能是一个错误的名称选择)是一个标识类型的值。例如,有时测试结果可能是一个浮点,然后我们就有了float_标记。
#ifdef __linux__ // or whatever you have there
#define START_TESTS()     std::array gTestStrings = {
#define END_TESTS()       };
#define TEST(expr, str)   TestString{__LINE__, str, unsigned_tag},
#else
#define START_TESTS()     {
#define END_TESTS()       }
#define TEST(expr, ...)   do{ \
    const auto _val = (expr); \
    write_uart(__LINE__); \
    write_uart(_val); \
} while(0)
#endif

int main() {
   START_TESTS()
      TEST(testPotentiometer(pot1), "Potentiometer 1 test result %u");
      TEST(testPotentiometer(pot2), "Potentiometer 2 test result %u");
   END_TESTS()
}
X(123, pot1, "Potentiometer 1 test result %u")
X(124, pot2, "Potentiometer 2 test result %u")
START_TESTS()
 ...
#define X(id, pot, text)                                 \
    do {                                                 \
        const unsigned potres = testPotentiometer(pot);  \
        write_uart(id);                                  \
        write_uart(potres);                              \
        TEST_PRINT(text, potres);                        \
    } while(0);
#include "pot_tests.h"
#undef X
 ...
END_TESTS()
std::array gTestStrings = {
    ... other strings ....
    #define X(id, pot, text)  TestString{id, text, unsigned_tag},
    #include "pot_tests.h"
    #undef X
    ... more strings ....
};