C++学习笔记之基础语法
基础语法
switch和if区别
先看一下switch和if汇编代码的区别:
int a = 3;
00007FF6A1831B4C mov dword ptr [a],3
if (a == 1)
00007FF6A1831B56 cmp dword ptr [a],1
00007FF6A1831B5D jne main+164h (07FF6A1831B74h)
{
cout << a;
00007FF6A1831B5F mov edx,dword ptr [a]
00007FF6A1831B65 mov rcx,qword ptr [__imp_std::cout (07FF6A1841150h)]
00007FF6A1831B6C call qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF6A18411E0h)]
00007FF6A1831B72 jmp main+195h (07FF6A1831BA5h)
}
else if (a == 2)
00007FF6A1831B74 cmp dword ptr [a],2
00007FF6A1831B7B jne main+182h (07FF6A1831B92h)
{
cout << a;
00007FF6A1831B7D mov edx,dword ptr [a]
00007FF6A1831B83 mov rcx,qword ptr [__imp_std::cout (07FF6A1841150h)]
00007FF6A1831B8A call qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF6A18411E0h)]
}
else
00007FF6A1831B90 jmp main+195h (07FF6A1831BA5h)
{
cout << a;
00007FF6A1831B92 mov edx,dword ptr [a]
00007FF6A1831B98 mov rcx,qword ptr [__imp_std::cout (07FF6A1841150h)]
00007FF6A1831B9F call qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF6A18411E0h)]
}
switch (a)
00007FF6A1831BA5 mov eax,dword ptr [a]
00007FF6A1831BAB mov dword ptr [rbp+154h],eax
00007FF6A1831BB1 cmp dword ptr [rbp+154h],1
00007FF6A1831BB8 je main+1B5h (07FF6A1831BC5h)
00007FF6A1831BBA cmp dword ptr [rbp+154h],2
00007FF6A1831BC1 je main+1CAh (07FF6A1831BDAh)
00007FF6A1831BC3 jmp main+1DFh (07FF6A1831BEFh)
{
case 1:
cout << a;
00007FF6A1831BC5 mov edx,dword ptr [a]
00007FF6A1831BCB mov rcx,qword ptr [__imp_std::cout (07FF6A1841150h)]
00007FF6A1831BD2 call qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF6A18411E0h)]
break;
00007FF6A1831BD8 jmp main+1F2h (07FF6A1831C02h)
case 2:
cout << a;
00007FF6A1831BDA mov edx,dword ptr [a]
00007FF6A1831BE0 mov rcx,qword ptr [__imp_std::cout (07FF6A1841150h)]
00007FF6A1831BE7 call qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF6A18411E0h)]
break;
00007FF6A1831BED jmp main+1F2h (07FF6A1831C02h)
default:
cout << a;
00007FF6A1831BEF mov edx,dword ptr [a]
00007FF6A1831BF5 mov rcx,qword ptr [__imp_std::cout (07FF6A1841150h)]
00007FF6A1831BFC call qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF6A18411E0h)]
break;
}
从上面的代码可以看出,正常情况下switch和if的性能没什么区别:
- if按顺序执行判断,如果条件满足则执行对应的语句并退出条件判断;如果条件不满足则跳过对应的语句,执行下一个条件判断。
- switch先判断所有条件,如果条件满足则跳转到对应的语句,执行语句,直到遇到break时退出。
其实,编译器实现switch语句有三种方式:逐条件判断、跳转表、二分查找法,具体情况参考C++性能switch语句
枚举定义及作用域
枚举使用时注意作用域的问题:
enum MONTH // 不限定作用域
{
JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE,
JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER
};
const int NOVEMBER = 1; //重定义错误
上面的代码会由于枚举作用域的问题出现重定义错误,参考 C++11 Enum枚举使用心得 使用限定作用域的枚举类型:
enum class DAY // 限定作用域
{
MONDAY, TUESDAY, WEDNESDAY, THURSDAY,
FRIDAY, SATURDAY, SUNDAY
};
DAY day = DAY::SUNDAY; // OK
int day = DAY::SUNDAY; //错误,限定作用域的枚举类型无法通过隐式转换到其他类型
注:由于枚举成员是const,因此建议用定义枚举成员用大写。
结构体数据耐齐--缺省对齐原则
字节对齐的细节和具体编译器实现相关,参考32、64位编译器各类型大小和字节对齐,一般满足三个准则:
- 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
- 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;
- 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。
结构体作为数据成员的对齐规则:在一个struct中包含另一个struct,内部struct应该以它的最大数据成员大小的整数倍开始存储。
struct S1
{
char x;
int z;
short y;
};
struct S2
{
char x;
short y;
int z;
};
cout << sizeof(S1) << endl; // 12
cout << sizeof(S2) << endl; // 8
在编码时,可以动态修改字节对齐方式,参考关于字节对齐、设置编译器的内存对齐方式(C++):
Visual C++:
- 使用伪指令#pragma pack (n),编译器将按照n个字节对齐。
- 使用伪指令#pragma pack (),取消自定义字节对齐方式。
g++:
- __attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。
- attribute ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。
函数重载overload与C++Name Mangling
可以使用undname工具查看函数的真实名称,代码如下:
int test(int a)
{
return a;
}
int test(double a)
{
return int(a);
}
使用Notepad++打开编译后的obj文件,搜索“test”得到如下内容:
?test@@YAHH@Z
?test@@YAHN@Z
在cmd中进入undname.exe所在的路径(系统内会有多个undname.exe,根据IDE的情况选择即可),我使用的是下面的路径:
cd C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\bin\Hostx86\x64\
调用undname.exe,输入以下命令:
undname ?test@@YAHH@Z
得到函数的真实名称:
Undecoration of :- "?test@@YAHH@Z"
is :- "int __cdecl test(int)"
同理,可得到:
Undecoration of :- "?test@@YAHN@Z"
is :- "int __cdecl test(double)"
指向函数的指针与返回指针的函数
每一个函数都占用一段内存单元,它们有一个起始地址,指向函数入口地址的指针称为函数指针。
形式:数据类型(*指针变量名)(参数表);
举例:int (*p)(int);
与返回指针的函数之间区别:
- int (*p) (int); //是指针,指向一个函数入口地址
- int* p (int); //是函数,返回的值是一个指针
C++学习笔记之基础语法的更多相关文章
- Java学习笔记之---基础语法
Java学习笔记之---基础语法 一. Java中的命名规范 (一)包名 由多个单词组成时,所有字母小写(例如:onetwo) (二)类名和接口 由多个单词组成时,所有单词首字母大写(例如:OneTw ...
- 2020寒假学习笔记14------Python基础语法学习(三)
今天学习了Python的基础语法,其中学的内容有: 比较运算符.逻辑运算符.同一运算符.整数缓存问题.基本运算符.复合复制运算符.运算符优先级问题.字符串基本特点.字符串的编码.空字符串和len()函 ...
- Hive学习笔记:基础语法
Hive基础语法 1.创建表 – 用户表 CREATE [EXTERNAL外部表] TABLE [IF NOT EXISTS 是否存在] HUserInfo ( userid int comment ...
- 【C语言C++编程学习笔记】基础语法,第一个简单的实例编程入门教程!
C语言/C++编程学习:一个简单的实例 让我们来看一个简单的C语言程序.从下面的程序可以看出编写C语言程序的一些基本特征. 如果你能知道该程序将会在显示器上显示一些内容,那说明你还是知道一些的! ...
- PHP学习笔记01——基础语法
<!DOCTYPE html> <html> <?php // 1.使用$加变量名来表示变量,php是弱类型语言,不要求在使用变量前声明,第一次赋值时变量才被创建 $a ...
- 01-Python学习笔记-基础语法
Python标识符 -d 在解析时显示调试信息 -O 生成优化代码 ( .pyo 文件 ) -S 启动时不引入查找Python路径的位置 - ...
- java学习笔记之基础语法(一)
1.java语言基础由关键字.标识符.注释.常量和变量.运算符.语句.函数和数组等组成. 2.1关键字 定义:被java语言赋予了特殊含义的单词 特点:关键字中所有的字母都是小写. 2.2用于定义数据 ...
- Java学习笔记之基础语法(顺序,条件,循环语句)
顺序结构:自上而下 条件分支选择结构: if条件语句 1,一旦某一个分支确定执行以后,其他分支就不会执行.if后面的条件必须是boolean类型 2,if 后面如果不加大括号,默认相邻的下一 ...
- Java学习笔记之基础语法(数据类型)
8种基本数据类型 整型: byte[1字节] short[2字节] int[4字节] long[8字节] 1,四种整型之间的区别:申 ...
- Python 学习笔记(基础语法 restful 、 Flask 和 Requests)
input 函数 #!/usr/bin/env python3 name = input("\n\n按下 enter 键后退出.") print(name) print() 在 p ...
随机推荐
- GDB调试程序 [补档-2023-07-19]
gdb调试 它是gcc的调试工具,调试工具都能干什么就不多说了. 7-1生成调试信息 在使用gcc编译c/c++的程序时,需要在编译命令中加入 -g 这一参数,它可以为你显示函数名,变量名 等 ...
- 监控Celery不一定非要使用Flower
运维平台中有许多的周期/定时/异步任务,例如证书扫描.数据备份.日志清理.线上作业等等,这些任务的执行都是借助于Celery来完成的.任务多了之后就会遇到一系列的问题,例如我之前写过的将任务分多队列来 ...
- 论文精读:用于少样本图像识别的语义提示(Semantic Prompt for Few-Shot Image Recognition)
原论文于2023.11.6撤稿,原因:缺乏合法的授权,详见此处 Abstract 在小样本学习中(Few-shot Learning, FSL)中,有通过利用额外的语义信息,如类名的文本Embeddi ...
- 使用Dapr和.NET 6.0进行微服务实战系列
大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 本文是<使用Dapr和.NET 6.0进行微服务实战>的第1篇引言部分 ...
- Proxmox的local-lvm改文件存储,提升运行速度
介绍 Proxmox的缺省安装会创建 local 和 local-lvm 两个存储.其中local大约磁盘容量的10%,存储类别为目录. local-lvm的存储类别为 lvm-thin. 实际使用中 ...
- DBGRIDEH 底部多列 发现
1.设置底部行数 2.点击footers 单独对每一行进行设置 3.单独对这两行 进行设置 5.看下辅助 所以用的时候可以这样用:WeiTopTradeShow.FieldColumns['top_x ...
- IDEA中使用ChatGPT
IDEA中使用ChatGPT 在IDEA中安装ChatGPT插件,可以帮助写基础逻辑代码,提高工作效率和学习效率,有兴趣可以玩一下. 插件名为 Bito. 1. 什么是Bito Bito是一款在Int ...
- Git Conventional Commits (Git代码提交说明规范)
Conventional Commits (代码提交说明规范) Conventional Commits 是关于Git Commit 提交代码时, 填写的说明文字的一个规范. 这个规范提供了一套易于理 ...
- OCP试题解析之052-- DROP PROFILE app_user
133.You created a profile APP_USER and assigned it to the users. After a month, you decide to drop t ...
- PL/SQL相关的数据字典
PL/SQL相关的数据字典 http://www.oracle.com/technetwork/issue-archive/2012/12-nov/o62plsql-1851968.html 有时候, ...