宏与125元

作者通过一个实际的项目案例,展示了如何利用宏定义简化内存分配的过程,并对其带来的效率提升进行了量化分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今年7月初,我作为课程设计的一名负责人,领导了一个连我在内4人的开发团队,开发了一个简易的“航班订票系统”。我定义了所需的数据结构,包括这样一个struct:

typedef struct _passenger
{
    /* 乘客数据,略去 */
    struct _passenger * next;
} PASSENGER, *PPASSENGER;

这之后每每要新建结点的时候,都得这么写:

PPASSENGER p = (PPASSENGER)malloc( sizeof( PASSENGER ) );

这一长串的代码使我厌烦,我便灵机一动,借用了C++之中operator new的形式,在我的头文件中写下了如下的一个宏:

#define NEW( type, count ) (type *)malloc( sizeof( type ) * count )

于是,我新建结点的代码便成了:

PPASSENGER p = NEW( PASSENGER, 1 );

足足少用了20个字符,我极为得意,自认为这是我十年来写下的最有创意的代码之一。

也许有的朋友不以为意,认为这算不了什么。那么请听我算上一笔帐吧:假如我是一个程序员,打字速度是1ch/s(当然慢得过分了,好在是假设),而我的身价奇高,挣钱速度是1RMB/s。以此计算,如果我在我的程序中需要写10行新建结点的代码,那么这个宏将为我节省20 * 10 - 75 = 125 (s)的时间(注:所谓75s,为加上NEW宏中换行符之后的回车符之故)。换算成人民币,就是125元。

正是以上的这件小事,成为了我这《随想》的缘起。

C++之父Bjarne Stroustrup曾经说过,绝不应该去使用宏,除非你不得不这样做。是的,自C诞生以来,宏便承载了太多的大是与大非——很多精巧的设计来自于令人拍案叫绝的宏,比如微软MFC类库中的消息映射;很多难以察觉的错误亦是来自于斯,比如这个老掉牙的例子:

#define macro( a, b ) a * b
int x = macro( 2, 3 ); // x == 2 * 3 == 6
int y = macro( 1 + 1, 3 ); // y == 1 + 1 * 3 == 4

C++之中倒是为宏设计了替代品:const常量、inline函数与模板。比如以下的宏:

#define NULL 0

在C++中就可以用以下的代码代替:

const int NULL = 0;

另外,还有宏函数:

#define max( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )

也可以由inline模板函数代替:

template < typename T > inline max( const T& a, const T& b )
{
    return ( ( a > b ) ? a : b );
}

如此说来,宏倒大有被取代之势了。

不过,宏所能给我带来的那125元的收益,却是const、inline和template不能取代的。

<think>我们正在处理一个关于ROS编译错误的问题。错误信息是:`'const class std::__cxx11::basic_string<char>' has no member named '__getMD5Sum'`。根据引用[2]和引用[3]的信息,这类错误通常C++的ABI(应用程序二进制接口)问题有关,特别是在不同版本的gcc/g++编译器之间。 在ROS中,消息类型(如`std_msgs::String`)在底层会使用到消息特征(message traits)来获取消息的MD5校验和、数据类型等。错误信息表明,编译器在`std::string`(即`std::__cxx11::basic_string<char>`)上找不到`__getMD5Sum`成员函数。这通常是因为ROS消息系统期望某种特定类型的字符串(可能是旧版的`std::string`,而不是C++11引入的新ABI),而当前代码中使用的字符串类型不符合预期。 根据引用[2]的说明,这个问题可能是因为编译环境和运行环境的gcc/g++版本不一致,导致对`std::string`的定义不同。解决这类问题的方法包括: 1. 统一编译环境和运行环境的编译器版本。 2. 在编译时使用定义`_GLIBCXX_USE_CXX11_ABI=0`来强制使用旧版ABI(即禁用C++11的字符串ABI)。 3. 如果问题出现在第三方库,确保所有依赖都使用相同的ABI进行编译。 在ROS的上下文中,我们可能需要检查以下几个方面: - 确保整个ROS工作空间(包括所有包)都使用相同版本的gcc/g++编译。 - 如果使用了预编译的二进制包(如通过apt安装的ROS包),需要确认这些包是用哪种ABI编译的,然后调整我们自己代码的编译选项以匹配。 具体到当前错误,我们可以尝试在编译时添加定义`_GLIBCXX_USE_CXX11_ABI=0`。例如,在CMakeLists.txt中添加: ```cmake add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0) ``` 或者在编译命令中直接添加: ```bash -D_GLIBCXX_USE_CXX11_ABI=0 ``` 另外,引用[4]提到了一个类似的错误(尽管是关于`shared_ptr`的),它提醒我们检查代码中消息类型的正确使用。在ROS中,消息类型有特定的定义,我们需要确保使用ROS提供的消息类型(如`sensor_msgs::PointCloud2`)而不是直接使用PCL或其他库的类型,除非有正确的转换。但当前错误信息指向的是`std::string`,因此可能不是消息类型选择错误,而是ABI不匹配。 因此,建议的解决步骤: 1. 确认系统中gcc/g++的版本,并确保所有依赖都使用相同版本的编译器编译。 2. 尝试在编译时添加`_GLIBCXX_USE_CXX11_ABI=0`。 3. 如果问题仍然存在,检查ROS消息定义和代码中消息的使用是否正确。 注意:使用`_GLIBCXX_USE_CXX11_ABI=0`可能会带来其他问题,因为强制使用旧ABI可能系统中其他使用新ABI的库不兼容。因此,最好首先尝试统一编译器版本。 如果用户提供了更具体的环境信息(如ROS版本、Ubuntu版本、gcc版本等),我们可以给出更精确的建议。</think>### ROS消息特征编译错误分析 您遇到的错误`'const class std::__cxx11::basic_string<char>' has no member named '__getMD5Sum'`是典型的**C++ ABI兼容性问题**,主要发生在ROS消息系统C++标准库版本不匹配时。以下是详细分析和解决方案: #### 错误原因分析 1. **ABI版本冲突** ROS消息系统依赖`ros::message_traits`模板来提取消息的数据(如MD5校验和)。当编译器使用**C++11新ABI**(`std::__cxx11::basic_string`)编译代码,但ROS库使用**旧ABI**编译时,模板特化无法匹配新字符串类型[^2]。 2. **编译器版本不一致** 您的开发环境(如gcc/g++版本)ROS二进制包使用的编译环境不一致,导致对`std::string`的底层实现不同[^3]。 3. **消息特征机制失效** ROS通过模板特化`ros::message_traits::MD5Sum<Message>`获取消息MD5值。当`std::string`的ABI变化导致模板匹配失败时,系统误认为消息类型缺少`__getMD5Sum`成员[^4]。 #### 解决方案 ##### 方法1:强制使用旧版ABI(推荐) 在编译命令中添加ABI兼容: ```bash # CMakeLists.txt中添加 add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0) # 或命令行编译时添加 catkin_make -DCMAKE_CXX_FLAGS="-D_GLIBCXX_USE_CXX11_ABI=0" ``` 此方法强制编译器使用旧版`std::string`实现,ROS二进制包兼容[^2]。 ##### 方法2:统一编译环境 ```bash # 检查当前GCC版本 gcc --version # 安装ROS对应版本的编译器(例如ROS Noetic默认用gcc-9) sudo apt install gcc-9 g++-9 # 设置默认编译器 sudo update-alternatives --config gcc ``` ##### 方法3:源码编译ROS核心包 ```bash # 创建新工作空间 mkdir -p ~/ros_abi_ws/src cd ~/ros_abi_ws # 克隆核心软件包 vcs import src < https://raw.githubusercontent.com/ros/rosdistro/master/ros.rosinstall # 统一ABI后编译 catkin_make -DCMAKE_CXX_FLAGS="-D_GLIBCXX_USE_CXX11_ABI=0" ``` #### 验证步骤 1. 创建测试消息文件`test.cpp`: ```cpp #include <ros/ros.h> #include <std_msgs/String.h> int main() { std_msgs::String msg; ROS_INFO("MD5: %s", ros::message_traits::MD5Sum<std_msgs::String>::value()); return 0; } ``` 2. 使用统一ABI编译: ```bash g++ -D_GLIBCXX_USE_CXX11_ABI=0 test.cpp -I/opt/ros/noetic/include -lroscpp ``` 正常输出应为:`MD5: 992ce8a1687cec8c8bd883ec73ca41d1` > **关键提示**:若依赖第三方库(如PCL),需确保所有库使用相同ABI标志编译[^4]。混合ABI会导致链接时出现未定义符号错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值