机器人CPP编程基础-03变量类型Variables Types
……AI……
C++
#include<iostream> // 引入iostream库,这个库包含了对输入/输出进行操作所需的函数和对象
using namespace std; // 使用命名空间std,这样我们就可以直接使用std中的名字,而不用在每次使用时都写std::
main() // 定义程序的主函数
{
// cin - console input 这是从控制台输入数据,cin代表“console input”
int a; // 定义一个整数变量a
cin >> a; // 从控制台获取输入,并将输入的值存储在变量a中
cout << "Variable name a = " << a << endl; // 输出变量a的值和它的名字
string name,surname; // 定义两个字符串变量name和surname
cout << "Enter your name : "; // 输出提示信息,让用户输入他们的名字
cin >> name; // 从控制台获取输入,并将输入的值存储在变量name中
cout << "Enter your surname : "; // 输出提示信息,让用户输入他们的姓氏
cin >> surname; // 从控制台获取输入,并将输入的值存储在变量surname中
cout << "Welcome "<<name<<" "<<surname<<endl; // 输出欢迎信息,包含用户的名字和姓氏
}
C++中,输入是通过标准输入流(stdin)进行的,通常使用cin对象来实现。cin对象是istream类的实例,它提供了许多输入方法来读取不同类型的数据。
以下是一些常用的C++输入方法:
-
读取字符:
cpp复制代码
char ch; | |
cin >> ch; |
这将从标准输入流中读取一个字符,并将其存储在变量ch中。
-
读取字符串:
cpp复制代码
string str; | |
cin >> str; |
这将从标准输入流中读取一行字符串,并将其存储在变量str中。
-
读取整数:
cpp复制代码
int num; | |
cin >> num; |
这将从标准输入流中读取一个整数,并将其存储在变量num中。
-
读取浮点数:
cpp复制代码
double num; | |
cin >> num; |
这将从标准输入流中读取一个浮点数,并将其存储在变量num中。
-
读取多个相同类型的数据:
cpp复制代码
int a, b, c; | |
cin >> a >> b >> c; |
这将从标准输入流中连续读取三个整数,并将它们分别存储在变量a、b和c中。
-
读取一行数据:
cpp复制代码
string line; | |
getline(cin, line); |
这将从标准输入流中读取一行字符串,并将其存储在变量line中。注意,getline()函数会读取包括行末尾的换行符在内的整个行。
-
忽略一行数据:
cpp复制代码
cin.ignore(); |
这将忽略从标准输入流中读取的一行数据,包括其中的字符、数字和其他内容。
总之,C++的输入操作可以通过使用cin对象和其提供的方法来实现,适用于不同的数据类型和场景。
Arduino
#include <Arduino.h>
void setup() {
Serial.begin(9600); // 初始化串口通信,波特率为9600
}
void loop() {
int a;
Serial.println("Enter a number:"); // 提示用户输入一个数字
if (Serial.available() > 0) {
a = Serial.parseInt(); // 从串口读取输入的数字
Serial.print("Variable name a = ");
Serial.print(a);
Serial.println();
}
String name = "John"; // 假设默认名字为John
Serial.println("Enter your name (or just press Enter to use default name John):");
if (Serial.available() > 0) {
name = Serial.readString(); // 从串口读取输入的名字
}
Serial.print("Welcome ");
Serial.print(name);
Serial.println();
String surname = "Doe"; // 假设默认姓氏为Doe
Serial.println("Enter your surname (or just press Enter to use default surname Doe):");
if (Serial.available() > 0) {
surname = Serial.readString(); // 从串口读取输入的姓氏
}
Serial.print(name);
Serial.print(" ");
Serial.print(surname);
Serial.println();
delay(1000); // 等待1秒钟后重复循环
}
在Arduino IDE中,需要使用#include <Arduino.h>
来引入Arduino库,而不是#include<iostream>
。此外,Arduino IDE使用串口通信来与计算机进行交互,因此需要使用Serial.println()
和Serial.readString()
等函数来读取和输出数据。最后,代码中使用了delay()
函数来等待1秒钟,以便让用户有时间输入数据。
Arduino的C++输入主要通过其特有的Serial类实现。Arduino通过串口(Serial port)与计算机或其他设备进行通信。
以下是在Arduino中实现输入的一些基本方法:
-
使用Serial.read():这个函数从串口读取字节,并返回它们。如果没有可读的字节,该函数将返回-1。
c复制代码
int incomingByte = Serial.read(); // 读取一个字节,并将其存储在变量incomingByte中 |
-
使用Serial.available():这个函数检查是否有可从串口读取的字节。如果有,它将返回可读取的字节数。
arduino复制代码
if (Serial.available() > 0) { | |
// 读取输入 | |
} |
-
使用Serial.parseInt()或Serial.readString():这两个函数都是为了从串口读取数据并解析为整数或字符串。
arduino复制代码
int incomingInt = Serial.parseInt(); // 从串口读取并解析为整数 | |
String incomingString = Serial.readString(); // 从串口读取并解析为字符串 |
需要注意的是,Arduino的输入方法主要参考了Arduino的Print类和Stream类,但具体的实现方式可能会有所不同。在编写Arduino程序时,最好查阅相关文档,以确保正确使用相关函数和类。
ROS1
#include <ros/ros.h>
#include <std_msgs/String.h>
int main(int argc, char **argv)
{
// Initialize ROS node
ros::init(argc, argv, "my_node");
// Create a ROS node handle
ros::NodeHandle nh;
// Create a private node handle (optional)
ros::NodeHandle private_nh("~");
// Create a ROS timer (optional, for publishing at a specific rate)
ros::Timer timer = nh.createTimer(ros::Duration(1.0), boost::bind(&myCallbackFunction));
// Create a ROS Publisher (for publishing messages)
ros::Publisher pub = nh.advertise<std_msgs::String>("my_topic", 1000);
// Create a ROS Service Client (for calling services)
ros::ServiceClient client = nh.serviceClient<my_service>("my_service_name");
// Create a ROS Service Server (for handling service calls)
ros::ServiceServer server = nh.advertiseService("my_service_name", &myServiceCallback);
// Create a ROS message for publishing or subscribing to topics
std_msgs::String msg;
msg.data = "Hello, world!";
// Create a ROS console stream for printing messages to the console
ros::console::notifyInit();
std::string line;
while (getline(std::cin, line)) {
if (line == "exit") break;
roscpp::MessageOnConsole(line);
}
ros::console::shutdown();
return 0;
}
在ROS1(Robot Operating System 1)中,输入通常通过订阅特定主题的方式实现。ROS1中的主题是发布/订阅模型,允许节点(Nodes)之间进行通信。节点可以发布特定主题,而其他节点可以订阅这些主题以接收消息。
以下是在ROS1中实现C++输入的基本步骤:
-
创建ROS1 C++节点:首先,需要创建一个ROS1 C++节点,该节点将订阅特定主题并处理接收到的消息。
-
包含必要的头文件:在C++源文件中,需要包含ROS1相关的头文件,以便使用ROS1的功能和数据类型。
cpp复制代码
#include <ros/ros.h> | |
#include <std_msgs/String.h> |
-
创建回调函数:定义一个回调函数,该函数将在接收到特定主题的消息时被调用。在回调函数中,可以处理接收到的消息并进行必要的操作。
cpp复制代码
void messageCallback(const std_msgs::String::ConstPtr& msg) | |
{ | |
// 处理接收到的消息 | |
std::string receivedMessage = msg->data; | |
// 执行其他操作... | |
} |
-
初始化ROS1节点:在
main()
函数中,需要初始化ROS1节点并设置回调函数。
cpp复制代码
int main(int argc, char** argv) | |
{ | |
// 初始化ROS1节点 | |
ros::init(argc, argv, "my_node"); | |
// 创建节点句柄 | |
ros::NodeHandle nh; | |
// 订阅特定主题的消息,并设置回调函数 | |
ros::Subscriber sub = nh.subscribe("my_topic", 1000, messageCallback); | |
// 进入循环,等待消息 | |
ros::spin(); | |
return 0; | |
} |
- 编译和运行:将C++源文件编译为可执行文件,并将其与ROS1环境一起运行。确保正确设置ROS1环境变量和依赖项。
这是一个简单的示例,展示了如何在ROS1中使用C++实现输入。根据实际需求,您可能还需要处理不同类型的消息、设置发布者(Publisher)等。详细的ROS1开发指南和文档可参考官方网站。
AI无穷生成,也是十分恐怖的。如何才好用呢?
C++20引入了一些新的输入和输出(I/O)功能,包括文件流、字符串流、格式化输入和输出等。下面详细介绍这些功能。
- 文件流
C++20引入了std::ifstream
和std::ofstream
,分别用于读取和写入文件。std::ifstream
用于从文件中读取数据,而std::ofstream
用于将数据写入文件。
以下是一个简单的示例,演示如何使用文件流读取和写入数据:
c复制代码
#include <iostream> | |
#include <fstream> | |
#include <string> | |
int main() { | |
// 创建一个输入文件流对象 | |
std::ifstream inputFile("input.txt"); | |
// 从输入文件流中读取数据 | |
std::string line; | |
while (std::getline(inputFile, line)) { | |
std::cout << line << std::endl; | |
} | |
// 创建一个输出文件流对象 | |
std::ofstream outputFile("output.txt"); | |
// 将数据写入输出文件流 | |
outputFile << "Hello, World!" << std::endl; | |
return 0; | |
} |
在上面的示例中,我们使用std::ifstream
从名为“input.txt”的文件中读取数据,并使用std::getline
逐行读取数据。然后,我们使用std::ofstream
将数据写入名为“output.txt”的文件中。
- 字符串流
C++20还引入了std::istringstream
和std::ostringstream
,分别用于从字符串中读取和将数据写入字符串。这些类可以方便地将字符串转换为其他数据类型,并可以轻松地将数据存储在字符串中。
以下是一个简单的示例,演示如何使用字符串流读取和写入数据:
c复制代码
#include <iostream> | |
#include <sstream> | |
#include <string> | |
int main() { | |
// 创建一个输入字符串流对象 | |
std::istringstream inputString("123 456 789"); | |
// 从输入字符串流中读取数据 | |
int a, b, c; | |
inputString >> a >> b >> c; | |
std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl; | |
// 创建一个输出字符串流对象 | |
std::ostringstream outputString; | |
// 将数据写入输出字符串流 | |
outputString << "Hello, World!" << std::endl; | |
std::cout << outputString.str() << std::endl; | |
return 0; | |
} |
在上面的示例中,我们使用std::istringstream
从字符串“123 456 789”中读取三个整数。然后,我们使用std::ostringstream
将字符串“Hello, World!”写入字符串流中,并使用str()
方法将其转换为字符串。
- 格式化输入和输出
C++20引入了新的格式化输入和输出功能,可以更方便地控制数据的格式。这些功能包括控制输出格式、控制浮点数精度、设置宽度和填充字符等。
以下是一个简单的示例,演示如何使用格式化输出控制数据的格式:
c复制代码
#include <iostream> | |
#include <iomanip> | |
int main() { | |
int x = 123; | |
double y = 3.14159; | |
// 使用格式化输出控制数据的格式 | |
std::cout << std::setw(10) << std::setprecision(4) << std::fixed << x << " " << y << std::endl; | |
return 0; | |
} |
在上面的示例中,我们使用std::setw
设置输出的宽度为10个字符,使用std::setprecision
设置浮点数的精度为4位小数,并使用std::fixed
指定浮点数以固定点表示。输出结果如下:
复制代码
123 3.1416 |
除了格式化输出,C++20还提供了格式化输入功能。以下是一个简单的示例,演示如何使用格式化输入读取整数和浮点数:
c复制代码
#include <iostream> | |
#include <iomanip> | |
#include <string> | |
#include <sstream> | |
int main() { | |
std::string input = "123 3.14159"; | |
std::istringstream inputStream(input); | |
int x; | |
double y; | |
// 使用格式化输入读取整数和浮点数 | |
inputStream >> std::setw(10) >> x >> y; | |
std::cout << "x = " << x << ", y = " << y << std::endl; | |
return 0; | |
} |
在上面的示例中,我们使用std::istringstream
将字符串“123 3.14159”转换为一个字符串流。然后,我们使用std::setw
设置输入的宽度,并使用>>
运算符从字符串流中读取整数和浮点数。输出结果如下:
c复制代码
x = 123, y = 3.1416 |
- 结构化绑定
C++20还引入了结构化绑定功能,可以方便地同时访问结构体或联合体的多个成员。
以下是一个简单的示例,演示如何使用结构化绑定:
c复制代码
#include <iostream> | |
struct Person { | |
std::string name; | |
int age; | |
}; | |
int main() { | |
Person p = {"Alice", 25}; | |
// 使用结构化绑定同时访问Person的成员 | |
std::cout << p.name << " is " << p.age << " years old." << std::endl; | |
return 0; | |
} |
输出结果为:
复制代码
Alice is 25 years old. |
除了结构体,结构化绑定也可以用于联合体和数组。以下是一个示例,演示如何使用结构化绑定访问联合体和数组的成员:
c复制代码
#include <iostream> | |
#include <array> | |
union Uint8 { | |
unsigned char value; | |
struct { | |
unsigned char least_significant_byte : 8; | |
}; | |
}; | |
int main() { | |
Uint8 u = {0x12}; | |
// 使用结构化绑定访问联合体的成员 | |
std::cout << u.least_significant_byte << std::endl; | |
std::array<int, 3> a = {1, 2, 3}; | |
// 使用结构化绑定访问数组的成员 | |
std::cout << a[0] << " " << a[1] << " " << a[2] << std::endl; | |
return 0; | |
} |
输出结果为:
makefile复制代码
12 | |
1 2 3 |
通过使用结构化绑定,可以方便地同时访问结构体、联合体和数组的多个成员,提高了代码的可读性和编写效率。
- 范围for循环
C++20引入了范围for循环(Range-based for loop),可以方便地遍历容器(如数组、向量、列表等)和迭代器范围。
以下是一个简单的示例,演示如何使用范围for循环遍历数组:
c复制代码
#include <iostream> | |
#include <array> | |
int main() { | |
std::array<int, 5> a = {1, 2, 3, 4, 5}; | |
// 使用范围for循环遍历数组 | |
for (const auto &elem : a) { | |
std::cout << elem << " "; | |
} | |
std::cout << std::endl; | |
return 0; | |
} |
输出结果为:
复制代码
1 2 3 4 5 |
除了数组,范围for循环也可以用于其他容器,如向量、列表等。以下是一个示例,演示如何使用范围for循环遍历向量:
c复制代码
#include <iostream> | |
#include <vector> | |
int main() { | |
std::vector<int> v = {1, 2, 3, 4, 5}; | |
// 使用范围for循环遍历向量 | |
for (const auto &elem : v) { | |
std::cout << elem << " "; | |
} | |
std::cout << std::endl; | |
return 0; | |
} |
输出结果为:
复制代码
1 2 3 4 5 |
通过使用范围for循环,可以方便地遍历容器和迭代器范围,而无需手动使用索引。这使得代码更加简洁和易于阅读。
- 初始化列表
C++20引入了初始化列表(Initializer List)语法,可以方便地对容器和其他变量进行初始化。
以下是一个示例,演示如何使用初始化列表对向量进行初始化:
c复制代码
#include <iostream> | |
#include <vector> | |
int main() { | |
// 使用初始化列表对向量进行初始化 | |
std::vector<int> v = {1, 2, 3, 4, 5}; | |
// 使用范围for循环遍历向量并输出 | |
for (const auto &elem : v) { | |
std::cout << elem << " "; | |
} | |
std::cout << std::endl; | |
return 0; | |
} |
输出结果为:
复制代码
1 2 3 4 5 |
除了向量,初始化列表还可以用于初始化其他类型,如结构体、联合体等。以下是一个示例,演示如何使用初始化列表对结构体进行初始化:
c复制代码
#include <iostream> | |
struct Point { | |
int x; | |
int y; | |
}; | |
int main() { | |
// 使用初始化列表对Point结构体进行初始化 | |
Point p = {10, 20}; | |
// 输出结构体的成员值 | |
std::cout << "x: " << p.x << ", y: " << p.y << std::endl; | |
return 0; | |
} |
输出结果为:
makefile复制代码
x: 10, y: 20 |
通过使用初始化列表,可以方便地对变量和容器进行初始化,使得代码更加简洁和易于阅读。
- 位运算
C++20引入了位运算的功能,可以使用“&”(按位与)、“|”(按位或)、“^”(按位异或)、“~”(按位非)、“>>”和“<<”(右移和左移)操作符进行位运算。
以下是一个示例,演示如何使用位运算对整数进行按位与、按位或和按位异或操作:
c复制代码
#include <iostream> | |
int main() { | |
int a = 5; // 二进制表示为 0101 | |
int b = 3; // 二进制表示为 0011 | |
// 按位与操作 | |
int and_result = a & b; // 0101 & 0011 = 0001,结果为1 | |
std::cout << "按位与的结果是:" << and_result << std::endl; | |
// 按位或操作 | |
int or_result = a | b; // 0101 | 0011 = 0111,结果为7 | |
std::cout << "按位或的结果是:" << or_result << std::endl; | |
// 按位异或操作 | |
int xor_result = a ^ b; // 0101 ^ 0011 = 0110,结果为6 | |
std::cout << "按位异或的结果是:" << xor_result << std::endl; | |
return 0; | |
} |
输出结果为:
makefile复制代码
按位与的结果是:1 | |
按位或的结果是:7 | |
按位异或的结果是:6 |
除了以上操作,C++20还支持位非、左移和右移运算。这些运算可以用于低级编程和高效的数据处理。
- 结构化绑定
C++20引入了结构化绑定功能,可以方便地同时访问结构体或联合体的多个成员。
以下是一个示例,演示如何使用结构化绑定:
c复制代码
#include <iostream> | |
struct Person { | |
std::string name; | |
int age; | |
}; | |
int main() { | |
Person p = {"Alice", 25}; | |
// 使用结构化绑定同时访问Person的成员 | |
std::cout << p.name << " is " << p.age << " years old." << std::endl; | |
return 0; | |
} |
输出结果为:
复制代码
Alice is 25 years old. |
通过使用结构化绑定,可以方便地同时访问结构体或联合体的多个成员,而无需逐个单独访问它们。这使得代码更加简洁和易于阅读。
这些是C++20引入的一些重要功能。还有其他一些功能和改进,但这些是其中一些最重要的。
- 线程
C++20引入了线程库,可以方便地编写多线程程序。这个库包含了许多关于线程、任务和并发操作的新功能。
以下是一个简单的示例,演示如何使用线程库:
c复制代码
#include <iostream> | |
#include <thread> | |
void my_function(int x) { | |
std::cout << "Thread function called with argument: " << x << std::endl; | |
} | |
int main() { | |
// 创建一个新的线程,并让它执行my_function函数 | |
std::thread my_thread(my_function, 10); | |
// 在主线程中输出一条消息 | |
std::cout << "Main thread message" << std::endl; | |
// 等待my_thread线程执行结束 | |
my_thread.join(); | |
return 0; | |
} |
这个程序会创建一个新的线程,并让它执行my_function
函数。然后,主线程会输出一条消息,并等待新线程执行结束。
线程库还包括更多的功能,如任务并行化、线程同步、条件变量、原子操作等。这些功能可以让你更方便地编写并行和多线程程序。
- 三元运算符
C++20引入了三元运算符?:
,可以更方便地进行条件判断。这个运算符的语法如下:
c复制代码
condition ? expression1 : expression2 |
如果condition
为真,则表达式的值为expression1
;否则,表达式的值为expression2
。
以下是一个示例,演示如何使用三元运算符:
c复制代码
#include <iostream> | |
int main() { | |
int a = 10; | |
int b = 20; | |
// 使用三元运算符根据条件选择值 | |
int max_value = (a > b) ? a : b; | |
std::cout << "Max value: " << max_value << std::endl; | |
return 0; | |
} |
这个程序会输出Max value: 20
,因为当a > b
为假时,max_value
的值被赋为b
。
- 类型推导
C++20引入了类型推导的新功能,使得变量的类型可以自动推导得出。这个功能主要适用于范围for循环和三元运算符。
以下是一个示例,演示如何使用类型推导:
c复制代码
#include <iostream> | |
#include <vector> | |
int main() { | |
std::vector<int> numbers = {1, 2, 3, 4, 5}; | |
// 使用范围for循环和类型推导遍历numbers向量 | |
for (auto [first, second] : numbers) { | |
std::cout << first << " " << second << std::endl; | |
} | |
return 0; | |
} |
这个程序会输出:
makefile复制代码
1 2 | |
3 4 | |
5 |
在这个示例中,auto [first, second]
表示我们要创建一个新的变量first
和second
,它们的类型将由编译器根据numbers
向量的元素推导得出。
类型推导使得代码更加简洁,同时也提高了可读性。
- 模式匹配(Pattern Matching)
C++20引入了模式匹配的功能,可以使用match
关键字进行模式匹配的判断。这个功能主要适用于结构化绑定和类型推导。
以下是一个示例,演示如何使用模式匹配:
c复制代码
#include <iostream> | |
#include <variant> | |
enum class Color { Red, Green, Blue }; | |
struct RGB { | |
Color color; | |
int red; | |
int green; | |
int blue; | |
}; | |
int main() { | |
std::variant<RGB, std::string> value = RGB{Color::Red, 255, 0, 0}; | |
// 使用模式匹配和结构化绑定判断value的类型并访问其成员 | |
if (const auto &rgb = std::get_if<RGB>(&value)) { | |
switch (rgb->color) { | |
case Color::Red: | |
std::cout << "RGB color: Red" << std::endl; | |
break; | |
case Color::Green: | |
std::cout << "RGB color: Green" << std::endl; | |
break; | |
case Color::Blue: | |
std::cout << "RGB color: Blue" << std::endl; | |
break; | |
default: | |
std::cout << "Unknown color" << std::endl; | |
} | |
} else { | |
std::cout << "Value is not an RGB object" << std::endl; | |
} | |
return 0; | |
} |
- 泛型(Generic)
C++20引入了泛型的功能,可以使用<template>
标签定义泛型模板。这使得代码更加通用和可重用。
以下是一个示例,演示如何使用泛型:
c复制代码
#include <iostream> | |
template <typename T> | |
T sum(T a, T b) { | |
return a + b; | |
} | |
int main() { | |
int x = 5; | |
double y = 3.5; | |
// 使用泛型函数计算整数和浮点数的和 | |
std::cout << "Sum of " << x << " and " << y << ": " << sum(x, y) << std::endl; | |
return 0; | |
} |
这个程序会输出:
makefile复制代码
Sum of 5 and 3.5: 8.5 |
在这个示例中,我们使用template <typename T>
定义了一个泛型函数sum
,它可以接受任何类型的参数并返回它们的和。然后,我们使用该函数计算了一个整数和一个浮点数的和。
泛型的引入使得代码更加灵活和可重用。
- 范围for循环(Range-based for loop)
C++20引入了范围for循环的功能,可以方便地遍历容器(如向量、列表、集合等)和数组。
以下是一个示例,演示如何使用范围for循环:
c复制代码
#include <iostream> | |
#include <vector> | |
int main() { | |
std::vector<int> numbers = {1, 2, 3, 4, 5}; | |
// 使用范围for循环遍历numbers向量并输出每个元素的值 | |
for (const auto &num : numbers) { | |
std::cout << num << " "; | |
} | |
std::cout << std::endl; | |
return 0; | |
} |
这个程序会输出:
makefile复制代码
1 2 3 4 5 |
在这个示例中,我们使用for (const auto &num : numbers)
语法来遍历numbers
向量,其中num
是每个元素的一个引用。这种写法更加简洁明了,使得代码更加易于阅读和理解。
当然,除了上面提到的,C++20还有以下几个重要的功能:
- 概念(Concepts):提供了一种描述函数或类模板约束的方式,以确保只有符合特定概念的类型才能用于函数或类模板的实例化。这有助于提高代码的清晰度和可维护性。
- 协程(Coroutines):允许函数在执行过程中挂起(suspend),以便稍后继续执行。协程在异步编程、生成器等场景中非常有用。
- 模块(Modules):将相关代码打包到模块中,并使用
export
关键字将其导出。这有助于组织代码,提高编译速度和可维护性。 - 类型别名(Type aliases):可以使用
using
关键字定义类型别名,这有助于提高代码的可读性和可维护性。 - 结构化绑定(Structured binding):允许将一个数组、元组或其他复合类型的多个成员变量同时赋值给不同的变量。这有助于简化代码并提高可读性。
这些功能进一步增强了C++20的语法和功能,使其更加现代化和灵活。