C++杂谈
打印log的参数类型
在C++中,当你尝试打印一个变量时,需要注意以下几种类型可能需要转换。
uint32_t类型
对于uint32_t
类型的变量,你可以直接打印,因为C++的流插入运算符(<<)
已经为uint32_t
类型定义了。
当你尝试将uint32_t
类型的变量插入到输出流(如std::cout或LOG(INFO))/ LOG(ERROR)
时,C++会自动调用正确的函数来将uint32_t
类型的变量转换为字符串。
eg:对于uint32_t
类型的cnt0
,你可以直接写
LOG(INFO) << "Decoded structure count: " << cnt0;
// C++会自动将cnt0转换为字符串并打印出来。
uint8_t 和 int8_t类型
对于uint8_t
类型的变量,虽然它本质上是一个整数,但是C++会将其视为字符并尝试打印相应的字符,而不是数字。因此,为了打印uint8_t
类型的变量的数值,你需要使用static_cast<int>()
来将其转换为int
类型。
( 这两种类型在C++中通常被视为字符类型,所以当你尝试打印它们的时候,C++会尝试打印相应的字符,而不是数字。为了打印这些类型的变量的数值,你需要使用static_cast<int>()
来将其转换为int类型。)
enum 类型
枚举类型:枚举类型的变量在打印时也需要转换,因为C++默认不会打印枚举类型的数值。你可以使用static_cast<int>()
来将枚举类型的变量转换为int
类型。
ptr 指针类型
指针类型:如果你尝试打印一个指针,C++会打印指针的地址,而不是指针指向的值。如果你想打印指针指向的值,你需要使用*运算符
来解引用指针。
//cout 打印
int* ptr = new int(10);
std::cout << "Address of pointer: " << &ptr << std::endl; // 打印地址
std::cout << "Value of pointer: " << *ptr << std::endl; // 打印值
// 使用LOG(INFO)打印(如果是使用Google Test框架)
int* ptr = new int(10);
LOG(INFO) << "Address of pointer: " << &ptr; // 打印地址
LOG(INFO) << "Value of pointer: " << *ptr; // 打印值
(1)获取指针的地址时,使用取地址运算符&
。
(2)获取指针指向的值时,使用解引用运算符*
。
(3)在打印指针的地址时,要注意指针本身的地址而不是它指向的值的地址。
(4)在打印指针的值时,要使用解引用运算符*来获取指针指向的实际值。
Boolean 类型
布尔类型:布尔类型的变量在打印时会被转换为true或false。如果你想打印布尔类型的变量的数值(即0或1),你可以使用static_cast<int>()
来将其转换为int
类型。
问题解决
若函数GetMaxNodeIndex()
返回的类型是int64_t
,而你想将其赋值给uint8_t
类型的add_task_id
。这可能会导致数据丢失,因为int64_t
类型的范围远大于uint8_t
类型的范围。
int64_t
类型可以表示的整数范围是-9223372036854775808到9223372036854775807
,而uint8_t
类型可以表示的整数范围是0到255
。如果GetMaxNodeIndex()
返回的值超过255或者小于0,那么在赋值给add_task_id时,会发生溢出,导致add_task_id的值不正确。
如果你确定GetMaxNodeIndex()
返回的值总是在0到255之间,那么你可以使用static_cast<uint8_t>()
来将其转换为uint8_t
类型。
例如:
uint8_t add_task_id = static_cast<uint8_t>(task_dao.GetMaxNodeIndex()+1);
但是,如果GetMaxNodeIndex()
返回的值可能超过255或者小于0,那么你需要在赋值之前进行检查,以防止溢出。例如:
int64_t max_node_index = task_dao.GetMaxNodeIndex() + 1;
if (max_node_index < 0 || max_node_index > 255) {
// Handle error
} else {
uint8_t add_task_id = static_cast<uint8_t>(max_node_index);
}
在这个示例中,如果max_node_index
不在0到255之间,那么我们会进入错误处理代码。否则,我们会将max_node_index
转换为uint8_t
类型,并赋值给add_task_id
。
错误
(1)“void value not ignored as it ought to be“错误
在C语言中,如果出现"void value not ignored as it ought to be"的错误,它表示你正在尝试使用一个返回类型为void
的函数或表达式的结果,但是你没有对它进行任何操作或赋值。
在C语言中,void
是一种特殊的类型,用于表示一个函数或表达式没有返回值。它通常用于函数声明或定义中,以指示该函数不返回任何值。
所以,当你使用一个返回类型为void的函数或表达式的结果时,C编译器会发出警告或错误,提醒你已经忽略了它的返回值。
为了解决这个错误,你可以考虑增加对返回值的操作或者将它赋值给一个变量(如果返回值有意义)。或者,如果你的确不需要使用该函数或表达式的返回值,你可以在使用时明确地将其忽略,例如使用(void)函数名()
的方式,以告诉编译器你有意忽略这个返回值。
(2)c++ error:crosses initialization of errror:jump to case label [-fpermissive]
switch
语句中没有单独的区域块限制变量的生命周期,因此变量生命周期是从声明到switch结束。因此在case1
中声明的变量在case2
中也可以使用。
如果在case1
中声明并且对其进行初始化,而运行时直接跳入case2
就会导致变量不能初始化,从而导致程序运行期间的问题。编译器为了防止这个问题就会出错提示。
解决办法是将变量的定义放在switch
语句之前
// 存在问题的
int main(){
int i=2;
switch(i){
case 1:
int j = 0;
break;
case 2:
j++;
break;
default:
break;
}
return 0;
}
// 解决后 将变量的定义放在switch语句之前
int main(){
int i=2;
int j=0;
switch(i){
case 1:
j = 0;
break;
case 2:
j++;
break;
default:
break;
}
return 0;
}
// 或者使用大括号限定变量的生命周期
int main(){
int i=2;
switch(i){
case 1:
{
int j = 0;
}
break;
case 2:
j++;
break;
default:
break;
}
return 0;
}
VSCode配置(页面配置)
settings.json
# settings.json
{
"workbench.colorTheme": "Monokai",
"workbench.colorCustomizations": {
"[Monokai]":{
"sideBar.background": "#1e1f1c",
"editor.background": "#272822",
"editorWhitespace.foreground": "#5f5f5f",
"titleBar.activeBackground": "#1e3b5c",
"debugToolBar.border": "#f11054",
"titleBar.border":"#b11b34",
"tab.activeBackground": "#b11b34",
"editor.selectionHighlightBackground":"#f5dd09ab",
"editor.selectionBackground": "#e4d01ad3",
}
},
"editor.tokenColorCustomizations": {
"[Monokai]":{
"textMateRules": [
{ /* enum item */
"name": "Constants and enums",
"scope": [
"variable.other.constant",
"variable.other.enummember"
],
"settings": {
"foreground": "#4FC1FF",
}
},
{ /* 123456789 */
"name": "Number",
"scope": "constant.numeric",
"settings": {
"foreground": "#AC80FF"
}
},
{ /* 0x */
"name": "Units",
"scope": "keyword.other.unit",
"settings": {
"foreground": "#AC80FF"
}
},
{ /* //Comment */
"name": "Comment",
"scope": "comment",
"settings": {
"foreground": "#29961f"
}
},
{ /* 'x' "hello" ... */
"name": "String",
"scope": "string",
"settings": {
"foreground": "#E6DB74"
}
},
{ /* "%s %d %f %c ..." */
"name": "User-defined constant",
"scope": "constant.character, constant.other",
"settings": {
"foreground": "#E6DB74"
}
},
{ /* a,b,c i,j,k ... */
"name": "Variable",
"scope": "variable",
"settings": {
"fontStyle": "",
"foreground": "#e2e2e2"
}
},
{ /* if else for while return ... */
"name": "Keyword",
"scope": "keyword",
"settings": {
"foreground": "#F92672"
}
},
{ /* > < = ! + - */
"scope": "keyword.operator",
"settings": {
"foreground": "#d4d4d4"
}
},
{ /* sizeof */
"scope": [
"keyword.operator.expression",
"keyword.operator.cast",
"keyword.operator.sizeof",
"keyword.operator.alignof",
"keyword.operator.typeid",
"keyword.operator.alignas",
"keyword.operator.instanceof",
"keyword.operator.logical.python",
"keyword.operator.wordlike"
],
"settings": {
"foreground": "#ff80c0"
}
},
{ /* new */
"scope": [
"keyword.operator.new"
],
"settings": {
"foreground": "#6491c5"
}
},
{ /* void int char short long unsigned */
"name": "Storage",
"scope": "storage",
"settings": {
"foreground": "#ff80c0"
}
},
{ /* static extern */
"name": "Storage type",
"scope": "storage.type",
"settings": {
"fontStyle": "italic",
"foreground": "#ff80c0"
}
},
{ /* this self */
"name": "this.self",
"scope": "variable.language",
"settings": {
"foreground": "#ff91bf"
}
},
{ /* ClassName ... */
"name": "Class name",
"scope": [
"entity.name.type",
"entity.name.class",
"entity.name.namespace",
"entity.name.scope-resolution",
"entity.other.inherited-class"
],
"settings": {
"fontStyle": "",
"foreground": "#646bc5"
}
},
{ /* main test ... */
"name": "Function name",
"scope": "entity.name.function",
"settings": {
"fontStyle": "",
"foreground": "#28cdea"
}
},
{ /* argc argv ... */
"name": "Function argument",
"scope": "variable.parameter",
"settings": {
"foreground": "#c7c7c7"
}
},
{ /* define name */
"scope": [
"meta.preprocessor",
"entity.name.function.preprocessor"
],
"settings": {
"foreground": "#AC80FF"
}
},
]
}
},
"explorer.confirmDelete": false,
"remote.SSH.remotePlatform": {
"bd1": "linux",
"aj102c": "linux",
"b125": "linux",
"b115": "linux",
"dcu-team": "linux",
"local-docker": "linux",
"aj102-docker": "linux",
"10.32.237.30": "linux"
},
"cmake.configureOnOpen": true,
"files.exclude": {
"**/.github": true,
"**/.gitmodules": true,
"**/*.gitignore": true,
"**/*.o": true,
"**/*.scc": true,
"build": true
},
"files.autoGuessEncoding": true,
"editor.fontSize": 22,
"editor.lineHeight": 24,
"C_Cpp.updateChannel": "Insiders",
"C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: Google, IndentWidth: 4,TabWidth: 4, ColumnLimit: 0}",
"editor.tabCompletion": "on",
"editor.renderWhitespace": "all",
"workbench.editorAssociations": {
"*.o": "default"
},
"update.mode": "none",
"C_Cpp.vcFormat.indent.namespaceContents": false,
"editor.detectIndentation": false,
"vsicons.dontShowNewVersionMessage": true,
"terminal.integrated.enableMultiLinePasteWarning": false,
"git.enableSmartCommit": true,
"Codegeex.Privacy": false,
"C_Cpp.inlayHints.parameterNames.suppressWhenArgumentContainsName": false,
"C_Cpp.inactiveRegionOpacity": 0.55,
"extensions.autoCheckUpdates": false,
"diffEditor.ignoreTrimWhitespace": false,
"git.ignoreLegacyWarning": true,
"cmake.showOptionsMovedNotification": false,
// "window.zoomLevel": -1,
"editor.tabSize": 8,
"window.zoomLevel": -0.5,// 左侧菜单栏的字体大小
"editor.mouseWheelZoom": true,// 按住ctrl可以设置代码的字体大小
"terminal.integrated.fontSize": 15, // 终端字体大小
"editor.wordWrap": "on", //终端自动换行
}
C++发展史
C++是一种通用的编程语言,它起源于1979年的C语言。Bjarne Stroustrup在贝尔实验室开发了C++,最初命名为"C with Classes"。随着时间的推移,C++经历了多个版本和更新,并成为目前最流行和广泛使用的编程语言之一。
以下是C++的发展史的主要里程碑:
-
1983年:Bjarne Stroustrup将"C with Classes"重命名为C++,并发布了第一个公开版本。
-
1985年:发布了C++的第一个商业版本。
-
1989年:发布了C++ 2.0版本,引入了多重继承、虚函数和异常处理等特性。
-
1998年:发布了C++ 98标准,该标准对语言进行了重大改进和扩展,并引入了模板、命名空间和异常规范等新特性。
-
2003年:发布了C++ 03标准,对前一版进行了一些修订和纠错。
-
2011年:发布了C++11标准(也称为C++0x),引入了许多新特性,如智能指针、lambda表达式、右值引用和移动语义等。
-
2014年:发布了C++14标准,对前一版进行了一些小幅度改进,并增加了一些新特性。
-
2017年:发布了C++17标准,引入了许多新特性,如结构化绑定、并行算法和文件系统库等。
-
2020年:发布了C++20标准,这是迄今为止最新的版本,引入了许多重要的特性,如概念、模块化编程和协程等。
C++在过去几十年中一直在不断发展和演变,并逐渐成为一种强大而灵活的编程语言。它被广泛应用于系统级编程、游戏开发、嵌入式设备、高性能计算和大数据处理等领域。同时,C++社区也非常活跃,不断推动语言的发展和改进。
值传递与引用传递
值传递和引用传递是C++中两种基本的参数传递方式,它们在函数调用时对参数的处理方式不同,具体区别如下:
-
值传递(Pass by Value):
- 复制: 当使用值传递时,实参的值会被复制到函数的形参中。这意味着函数内部对形参的修改不会影响到实参。
- 内存使用: 值传递可能会增加内存的使用量,因为需要为每个参数创建副本。
- 性能: 对于大型对象或复杂类型,值传递可能会因为复制操作而导致性能下降。
- 安全性: 值传递提供了较高的安全性,因为函数不能修改原始数据。
- 适用场景: 通常用于传递简单数据类型(如int、float等)或小型对象。
-
引用传递(Pass by Reference):
- 别名: 当使用引用传递时,形参是实参的一个别名。这意味着函数内部对形参的修改会影响到实参。
- 内存使用: 引用传递不会产生额外的内存开销,因为不会复制数据。
- 性能: 对于大型对象或复杂类型,引用传递可以提高性能,因为它避免了复制操作。
- 安全性: 引用传递降低了安全性,因为函数可以修改原始数据。
- 适用场景: 通常用于需要在函数内部修改实参的值,或者传递大型对象以避免复制开销。
-
const引用传递(Pass by const Reference):
- 这是引用传递的一个变体,它通过添加
const
关键字来防止函数内部修改实参。 - 它结合了值传递的安全性和引用传递的性能优势。
- 这是引用传递的一个变体,它通过添加
-
指针传递:
- 指针传递与引用传递类似,但它使用指针来访问数据。
- 指针传递可以提供更多的灵活性,例如可以传递空指针,但需要更多的注意来避免诸如空指针解引用等错误。
-
std::move和右值引用:
- 在C++11及以后的版本中,引入了
std::move
和右值引用的概念,允许以低成本的方式转移资源的所有权,特别是在移动语义中。
- 在C++11及以后的版本中,引入了
-
函数参数的默认值:
- 在引用传递中,不能为形参提供默认值,因为默认参数的机制与引用的语义不兼容。
-
临时对象:
- 值传递可以与临时对象一起使用,而引用传递则不能直接与临时对象一起使用,除非使用std::move将其转换为右值引用。