数据类型
- 枚举类型enum
enum MotorIndex {
kLeftMotor = 0,
kRightMotor = 1,
};
枚举常量必须是整数类型,可以当变量直接使用。
- struct结构
struct MotorStatus {
float current;
int16_t temperature;
int16_t temperature_MCU;
int16_t rpm;
int32_t counter;
int32_t counter_offset;
uint8_t status;
bool counter_reset;
//类变量初始化
MotorStatus() :
rpm(0), counter(0), status(0), counter_reset(false)
{ }
};
MotorStatus motorstatus[2];
motorstatus[0].current = 0;
- size_t
使用size_t可能会提高代码的可移植性、有效性或者可读性。
例:
size_t size=sizeof(i);//用sizeof操作得到变量i的类型的大小,
有时候会使用unsigned int,但是它有可能会影响设备的性能。
常见类型转换
-
static_cast
与dynamic_cast
:
前者提供的是编译时期的静态类型检测,后者提供的是运行时检测.dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。在类层次间进行上行转换,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全
static_cast
: 1)完成基础数据类型,2)同一个继承体系中类型的转换 3)任意类型与空指针类型void*之间的转换。
dynamic_cast
:使用多态的场景,增加了一层对真实调用对象类型的检查 -
const_cast
用于取出const属性,把const类型的指针变为非const类型的指针, -
reinterpret_cast
数据的二进制形式重新解释,但是不改变其值。这个操作符能够在非相关的类型之间转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝。在类型之间指向的内容不做任何类型的检查和转换。
如:
int i; char *ptr="hello freind!"; i=reinterpret_cast<int>(ptr);
static_cast<int>()....类似
- c_str()
string.c_str()返回字符串指针 (ROS_INFO中经常用来输出%s) strcpy
和memcpy
strcpy和memcpy都是标准C库函数,它们有下面的特点。
strcpy提供了字符串的复制。即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符。
已知strcpy函数的原型是:char* strcpy(char* dest, const char* src);
memcpy提供了一般内存的复制。即memcpy对于需要复制的内容没有限制,因此用途更广。
这两个函数也可以作为类型转换的使用。- atoi()和stoi()
atoi()的参数是 const char* ,因此对于一个字符串str我们必须调用 c_str()的方法把这个string转换成 const char类型的,而stoi()的参数是const string,不需要转化为 const char*;
stoi()会做范围检查,默认范围是在int的范围内的,如果超出范围的话则会runtime error
而atoi()不会做范围检查,如果超出范围的话,超出上界,则输出上界,超出下界,则输出下界 - to_string()
std::to_string(1);
将数值转化为字符串。返回对应的字符串。
字符串分割
- strtok函数
buf_spilt[0] = strtok(buf_c, delim1);
data_n = strtok(NULL, delim1);
参数与返回值都是char*,第一次使用时会分割出字符并返回左侧的字符串,并会保存分割位置的指针,再次使用并给出NULL参数,会继续进行分割,如果为发现分隔符,则返回NULL。此函数设计优劣都很明显,使用需谨慎。
//一个连续分割的例子
int datacheck = 1;
char *data_n = new char[20];
char *buf_c = new char[200];
char const *delim1 = "\r";
char const *delim2 = "=";
std::vector<std::string> buf_spilt(27);
strcpy(buf_c, buf_driver.c_str());
buf_spilt[0] = strtok(buf_c, delim1);
for (int i = 1; i < 26; ++i)
{
// ROS_INFO("%s", buf_spilt[i-1].c_str());
data_n = strtok(NULL, delim1);
if (data_n != NULL)
{
buf_spilt[i] = data_n;
}
else {
datacheck = 0;
i = 26;
}
}
// ROS_INFO("%s", buf_spilt[25].c_str());
if (datacheck == 1)
{
for (int i = 1; i < 26; i+=2)
{
char *buf_n = new char[20];
strcpy(buf_n, buf_spilt[i].c_str());
char *temp2 = strtok(buf_n, delim2);
if (temp2 == data_type[(i-1)/2])
{
temp2 = strtok(NULL, delim2);
num[(i-1)/2] = atoi(temp2);
}
}
}
- 使用find与string手写
std::vector<std::string> iqr::CasterHardware::BufferSpilt(std::string buf_driver, const char* delim) {
std::vector<std::string> data_type;
data_type.push_back(buf_driver);
int data_start = 0, data_stop = 0, i = 0;
while(data_stop != -1)
{
data_stop = buf_driver.find(delim, data_start);
// ROS_INFO("%i", data_stop);
if (data_stop != -1)
{
data_type.push_back(buf_driver.substr(data_start, data_stop));
// ROS_INFO("%s", data_type[i].c_str());
data_start = data_stop+1;
i++;
}
if (i != 0 && data_stop == -1)
{
data_type.push_back(buf_driver.substr(data_start));
// ROS_INFO("%s", data_type[i].c_str());
}
}
for (int i = 0; i < data_type.size(); ++i)
{
ROS_INFO("%s", data_type[i].c_str());
}
return data_type;
}
void split(const string& s, vector<string>& tokens, const string& delimiters = " ")
{
string::size_type lastPos = s.find_first_not_of(delimiters, 0);
string::size_type pos = s.find_first_of(delimiters, lastPos);
while (string::npos != pos || string::npos != lastPos) {
tokens.push_back(s.substr(lastPos, pos - lastPos));
lastPos = s.find_first_not_of(delimiters, pos);
pos = s.find_first_of(delimiters, lastPos);
}
}
- C++ 11之后可用正则表达式
std::string text = "Quick brown fox.";
std::regex ws_re("\\s+");
std::vector<std::string> v(std::sregex_token_iterator(text.begin(),
text.end(), ws_re, -1),std::sregex_token_iterator());
for(auto&& s: v)
std::cout<<s<<"\n";
更高版本会有更多的实现方式,考虑开发环境适合版本使用适合方法。
switch case区分字符串
C++中只能以数字类型作为参数。
可以使用map的方式,然后进行数据处理。
输出显示
- 长字符串
for (int i = 0; i < buf_driver.size(); i++) {
ROS_INFO("%c", *(buf_driver.c_str()+i));
}
指针与引用
int m;
int &n = m;
n 相当于 m 的别名, 既不是m的拷贝,也不是指向 m 的指针,n就是 m 。
引用的规则:
- 用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
- NULL 引用,引用必须与合法的存储单元关联(指针则可以是 NULL)。
- 引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。
以下示例程序中,k 被初始化为i的引用。
语句 k = j 并不能将 k 修改成为j的引用,只是把k的值改变成为 6。
由于 k 是 i 的引用,所以i的值也变成了 6。
int i = 5;
int j = 6;
int &k = i;
k = j; // k 和 i 的值都变成了 6;
引用的主要功能是传递函数的参数和返回值。
C++ 语言中,函数的参数和返回值的传递方式有三种:值传递、指针传递和引用传递。
以下是"值传递"的示例程序。
由于 Func1 函数体内的 x 是外部变量 n 的一份拷贝,改变 x 的值不会影响 n, 所以 n 的值仍然是 0。
void Func1(int x)
{
x = x + 10;
}
...
int n = 0;
Func1(n);
cout << "n = " << n << endl; // n = 0
以下是"指针传递"的示例程序。
由于 Func2 函数体内的 x 是指向外部变量 n 的指针,改变该指针的内容将导致 n 的值改变,所以 n 的值成为 10。
void Func2(int *x)
{
(* x) = (* x) + 10;
}
...
int n = 0;
Func2(&n);
cout << "n = " << n << endl; // n = 10
以下是"引用传递"的示例程序。
由于 Func3 函数体内的 x 是外部变量 n 的引用,x 和 n 是同一个东西,改变 x 等于改变 n,所以 n 的值成为 10。
void Func3(int &x)
{
x = x + 10;
}
...
int n = 0;
Func3(n);
cout << "n = " << n << endl; // n = 10
指针能够毫无约束地操作内存中的任何东西,尽管指针功能强大,但是非常危险。
如果的确只需要借用一下某个对象的"别名",那么就用"引用",而不要用"指针",以免发生意外。