可变后缀字符串的生成方法

项目场景:

在使用webots时, 发现webots里面, 构建的模型代码中的控制句柄是通过模型的名字:name(字符串)建立关系的, 官方的写法如下:

Motor *motor = robot->getMotor("motorname");

问题描述

提示:这里描述项目中遇到的问题:
那么最容易想到的写法当然是

#include <string>
typedef enum
{
	MOTO_IDX1 = 0,
	MOTO_IDX2,
	MOTO_IDX3,
	MOTO_IDX4,
	MOTO_TTL_NUM
}moto_idx_t;
std::motor_names[MOTO_TTL_NUM] = {	"motorname1",
									"motorname2",
									"motorname3",
									"motorname4"	};
Motor *motors[MOTO_TTL_NUM];
for(int i = 0; i<MOTO_TTL_NUM ;++i){
	motors[i] = robot->getMotor( motor_names[i] );
}

但这个写法感觉还是不够优雅, 因为motor_names数组得一个个添加, 并且名字格式写死, 并不方便后期的维护与修改.
因为之前有看过以下的写法,

// 第一种宏定义用法
#define LED_ON(x) HAL_GPIO_Write_Pin(LED##x##_Port,LED##x##_Pin,GPIO_PIN_SET);
LED_ON(1);
// 运行结果:
// 执行函数:HAL_GPIO_Write_Pin(LED1_Port,LED1_Pin,GPIO_PIN_SET);

// 第二种宏定义用法
#define hello(x) "hello"#x
printf(hello(1));
// 运行结果:
// 打印出:hello1

那么就想通过宏定义的方法来优雅实现, 所以理所当然地改了:

#include <string>
typedef enum
{
	MOTO_IDX1 = 0,
	MOTO_IDX2,
	MOTO_IDX3,
	MOTO_IDX4,
	MOTO_TTL_NUM
}moto_idx_t;
#define motor_name(x) "motor_name##x"
Motor *motors[MOTO_TTL_NUM];
for(int i = 0; i<MOTO_TTL_NUM ;++i){
	motors[i] = robot->getMotor( motor_name(i+1) );
}

修改后,程序有BUG,webots提示找不到"motor_name##i+1"
于是又换成第二种写法

#include <string>
typedef enum
{
	MOTO_IDX1 = 0,
	MOTO_IDX2,
	MOTO_IDX3,
	MOTO_IDX4,
	MOTO_TTL_NUM
}moto_idx_t;
#define motor_name(x) "motor_name"#x
Motor *motors[MOTO_TTL_NUM];
for(int i = 0; i<MOTO_TTL_NUM ;++i){
	motors[i] = robot->getMotor( motor_name(i+1) );
}

程序出了BUG,webots提示找不到"motor_namei+1"

原因分析:

提示:这里填写问题的分析:

  1. 写法一分析
    这个地方就是因为我从以下写法得到灵感

    // 第一种宏定义用法
    #define LED_ON(x) 	HAL_GPIO_Write_Pin(LED##x##_Port,LED##x##_Pin,GPIO_PIN_SET);
    LED_ON(1);
    // 运行结果
    // HAL_GPIO_Write_Pin(LED1_Port,LED1_Pin,GPIO_PIN_SET);
    

    然后自以为字符串可以同样操作, 但实际上, 在宏定义展开时, 在双引号" "里面的##是不会形成链接的, 而是保留下来, 所以调用motor_name(i+1)之后, 预处理时候只是将x替换成i+1, 所以结果是"motor_name##i+1", webot肯定找不到这个定义, 所以崩溃.

  2. 写法二分析
    众所周知, 宏定义展开发生在预处理阶段, 但有时候一不小心就容易忘记这一点而导致错误, 正如上面的写法二. 在预处理阶段, motor_name(i+1)会被展开成为"motor_namei+1"这个字符串, 所以在程序运行阶段, 变量i已经失去了它该有的价值, 它已经和"motor_namei+1"这个字符串融为一体, 所以每一个motors[i]都会指向
    "motor_namei+1"返回的结果, webot肯定找不到这个定义, 所以崩溃.


解决方案:

提示:这里填写该问题的具体解决方案:

由于宏定义是在预处理就完成了所有展开,所以要用宏定义的方法生成由变量来决定后缀的字符串是行不通的, 所以只能弃用宏定义, 最终实现如下:

#include <string>
typedef enum
{
	MOTO_IDX1 = 0,
	MOTO_IDX2,
	MOTO_IDX3,
	MOTO_IDX4,
	MOTO_TTL_NUM
}moto_idx_t;

const std::string gen_wheel_tag(int x){
  return "motor_name"+ std::to_string(x);
}

Motor *motors[MOTO_TTL_NUM];
for(int i = 0; i<MOTO_TTL_NUM ;++i){
	motors[i] = robot->getMotor( gen_wheel_tag(i+1) );
}

由这次经历, 也是体会到了基础知识的重要性, 故此文记之.

  • 17
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值