以c++的方式实现error类型的定义

一、背景

以前大量使用c语言进行嵌入式软件开发的时候,对于错误类型比较常见的方式大概有:

  • 使用define的宏定义
  • 使用enum的枚举

比如这里需要定义四个错误类型,成功,失败,严重错误,未定义错误。

如果使用宏定义的方式来定义,形如:

#define ERR_OK        0
#define ERR_FAIL      1
#define ERR_FATAL     2
#define ERR_UNDEFINED 3

如果使用枚举的方式来定义,形如:

typedef enum _eError
{
    ERR_Ok = 0,
    ERR_Fail,
    ERR_Fatal,
    ERR_Undefined,
}ErrorType;

从形式上来看,它们都非常的简洁轻量,但是在进行Debug的时候,如果输出的log中只是这些数值错误号的话,就非常的麻烦,还必须得时刻与定义的错误类型进行对比已确认到底是什么错误。

所以如果在输出log时,就能直接输出错误信息的字符串,那就会方便很多了。比如c语言当中的 errno就是错误号(数值),可以通过strerror(errno)的方式获取某错误号对应的错误信息的字符串。

当然如果我们自定义的错误类型也要实现这样的功能,那么除了以上的错误类型定义之外,还必须专门定制实现一些函数接口来让我们获取错误信息的字符串。

有时候,如果我们开发的软件是一个library的方式发布,很有可能我们会用到不同类别的错误类型,比如

  • 用于library接口的API的外部错误类型,供library的用户使用
  • 用于library内部的错误类型,供library的开发人员使用

这时,有可能需要开发两个获取错误信息的接口,也是比较麻烦的。

二、c++解决方案

如果你是像c一样使用c++的话,那这部分你就不需要看了,自行忽略吧,当我没写。

虽然c++被很多人说这样不好,那样不足,但不可否认,它还是有些好东西的。比如封装,重载等等。

这里我们需要做的就是使用c++的封装,重载等特性来实现错误类型的定义,并能方便的获取错误信息。

  • 首先定义错误类型的结构体:
struct ErrorType
{
    int code = 0;  /** error code( or number) */
    const char* desc = ""; /** the describe of error, aways not null */
};

你可能要说,你这里不也是像c一样使用字符串指针吗? 这里之所以要这样用,是为了节省空间,一个string对象的size有二三十个字节,略大了一点。

  • 其次是重载操作运算符,因为错误类型定义出来,其目的就是拿来使用的,赋值,对比等都是常用的操作
/** error type */
struct ErrorType
{
    int code = 0;  /** error code( or number) */
    const char* desc = ""; /** the describe of error, aways not null */

    ErrorType(int cd, const char* dsc)
        :code(cd), desc(dsc)
    {
    }

    inline bool operator==(const ErrorType& et) const
    {
        return (code == et.code);
    }

    inline bool operator!=(const ErrorType& et) const
    {
        return (code != et.code);
    }

    inline ErrorType& operator=(const ErrorType& et)
    {
        code = et.code;
        desc = et.desc;

        return *this;
    }


};

这里的对比包括了,相等和不相等两种,就以上实现绝大多数情况下就已经够用了。

2.1 用c++实现错误类型定义

还是以第一章为例,定义四种错误类型。 这里和第一章有一点不一样的是,声明是在头文件中进行的,但具体的定义是在cpp源文件中实现的。

先来看头文件(假设为:errorType.h)

/************************************************************************/
/** 这部分是为了兼容visual studio和gcc对于动态库类型导出修饰符 */
/** macro define for special tool chain. */
#if defined(__GNUC__) /** !!!for gcc */

#define G_GCC_VERSION(maj,min) \
        ((__GNUC__ > (maj)) || (__GNUC__ == (maj) && __GNUC_MINOR__ >= (min)))

/** define API export  macro */
#if G_GCC_VERSION(4,0) //for gcc(version >= 4.0)
#define G_DLL_EXPORT __attribute__((visibility("default")))
#else
#define G_DLL_EXPORT
#endif

#elif defined(_MSC_VER) /** !!!for visual studio */


/** auto define API export macro */
#if !defined(DLL_EXPORT) && defined(_WINDLL) //todo,process _USRDLL,_AFXDLL
#define DLL_EXPORT
#endif

#if defined (DLL_EXPORT)
#define G_DLL_EXPORT __declspec(dllexport)
#else
#define G_DLL_EXPORT __declspec(dllimport)

#endif

#else /** !!!for unknown tool chain */
///
#error "!!unspport this toolchain at now!!"
#endif /** !!! end of tool chain define */


/** general global variable decorate macro(for external reference ) */
#define G_VAR  extern G_DLL_EXPORT 

/** general const global variable decorate macro(for external reference ) */
#define G_CVAR G_VAR const 
/************************************************************************/

G_CVAR ErrorType ERR_OK;
G_CVAR ErrorType ERR_FAIL;
G_CVAR ErrorType ERR_FATAL;
G_CVAR ErrorType ERR_UNDEFINED;

源文件的具体实现(假设为:ErrorType.cpp):

G_CVAR ErrorType ERR_OK                         = { 0, "Success" }; 
G_CVAR ErrorType ERR_FAIL                       = { 1, "Fail" };
G_CVAR ErrorType ERR_FATAL                      = { 2, "Fatal" };
G_CVAR ErrorType ERR_UNDEFINED                  = { 3, "undefined" };

2.2 使用方式

这里用c++方式实现的错误类型定义和c语言的实现在使用方式上是差不多的。形如:

#include "ErrorType.h"


ErrorType func1()
{
    /** todo something */
    return ERR_OK;
}

ErrorType func2()
{
    ErrorType ret = ERR_OK;

    ret = func1();

    if (ret != ERR_OK)
    {
        /**这里就可以直接使用错误类型的 ‘desc’ 成员变量来获得错误信息的字符串,相当方便 */
        LOG("do func1 failed(%d, %s)\n", ret.code, ret.desc);
    }

    return ret;
}
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用 Fast DDS 实现 set 和 get 方法通信的 C++ 示例代码: ```c++ #include <fastrtps/attributes/ParticipantAttributes.h> #include <fastrtps/attributes/PublisherAttributes.h> #include <fastrtps/attributes/SubscriberAttributes.h> #include <fastrtps/Domain.h> #include <fastrtps/publisher/Publisher.h> #include <fastrtps/subscriber/Subscriber.h> #include <fastrtps/xmlparser/XMLProfileManager.h> using namespace eprosima::fastrtps; // 定义数据类型 struct MyDataType { int32_t id; std::string name; }; class MyReaderListener : public SubscriberListener { public: void onNewDataMessage(Subscriber *sub) override { MyDataType data; SampleInfo_t info; if (sub->takeNextData(&data, &info)) { std::cout << "Received data: " << data.name << std::endl; } } }; class MyWriter { public: MyWriter() { // 创建参与者 ParticipantAttributes participantAttrs; participantAttrs.rtps.builtin.domainId = 0; participantAttrs.rtps.builtin.leaseDuration = c_TimeInfinite; participantAttrs.rtps.setName("MyParticipant"); participant = Domain::createParticipant(participantAttrs); if (participant == nullptr) { std::cout << "Error creating participant" << std::endl; return; } // 创建发布者 PublisherAttributes publisherAttrs; publisherAttrs.topic.topicDataType = "MyDataType"; publisherAttrs.topic.topicName = "MyTopic"; publisher = Domain::createPublisher(participant, publisherAttrs, nullptr); if (publisher == nullptr) { std::cout << "Error creating publisher" << std::endl; return; } } void setData(const MyDataType& data) { // 发布数据 publisher->write(&data); } private: Participant *participant; Publisher *publisher; }; class MyReader { public: MyReader() { // 创建参与者 ParticipantAttributes participantAttrs; participantAttrs.rtps.builtin.domainId = 0; participantAttrs.rtps.builtin.leaseDuration = c_TimeInfinite; participantAttrs.rtps.setName("MyParticipant"); participant = Domain::createParticipant(participantAttrs); if (participant == nullptr) { std::cout << "Error creating participant" << std::endl; return; } // 创建订阅者 SubscriberAttributes subscriberAttrs; subscriberAttrs.topic.topicDataType = "MyDataType"; subscriberAttrs.topic.topicName = "MyTopic"; listener = new MyReaderListener(); subscriber = Domain::createSubscriber(participant, subscriberAttrs, listener); if (subscriber == nullptr) { std::cout << "Error creating subscriber" << std::endl; return; } } MyDataType getData() { // 从订阅者中获取数据 MyDataType data; SampleInfo_t info; if (subscriber->takeNextData(&data, &info)) { return data; } return {}; } private: Participant *participant; Subscriber *subscriber; MyReaderListener *listener; }; int main() { // 创建数据写入者和读取者 MyWriter writer; MyReader reader; // 设置数据并发布 MyDataType data; data.id = 1; data.name = "Alice"; writer.setData(data); // 获取数据并打印 MyDataType receivedData = reader.getData(); std::cout << "Received data: " << receivedData.name << std::endl; return 0; } ``` 以上代码演示了如何使用 Fast DDS 创建数据写入者和读取者,并通过发布/订阅模型实现数据的 set 和 get。在示例中,数据类型为 `MyDataType`,包括一个 `id` 和一个 `name` 字段,数据写入者使用 `MyWriter` 类,数据读取者使用 `MyReader` 类,数据写入者发布数据,数据读取者从订阅者中获取数据,并打印接收到的数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值