C++基础概念(上)
# 基础概念
1、静态编译类型,非动态(OC默认动态,Swift默认是静态)
2、区分大小写(敏感)
3、支持面向过程编程、面向对象编程和泛型编程(Swift支持泛型编程)
4、介于低级语言和高级语言之间
5、兼容大部分中低版本的C语法
6、面向对象四大特性:封装、抽象、继承、多态
7、标准库: C++ 三部分组成
基础语言、变量、数据类型和常量,等等
大量的 标准库函数,操作文件、字符串等
标准模板库操作数据结构等
8、通用性:一般C++代码在 Mac、UNIX、Windows、Alpha 计算机上都能通过编译
9、C++ 程序的源文件通常使用扩展名 .cpp(默认)、.cp 或 .c(少)
10、编译器: GNU 的 gcc 编译器适合于 C 和 C++ 编程语言的编译
11、基本语法组成:类对象、方法、变量
# 版本、库历史
发布时间 | 通称 | 备注 |
---|---|---|
2020 | C++20 | 第六个C++标准 |
2017 | C++17 | 第五个C++标准 |
2017 | coroutines TS | 协程库扩展 |
2017 | ranges TS | 提供范围机制 |
2017 | library fundamentals TS | 标准库扩展 |
2016 | concurrency TS | 用于并发计算的扩展 |
2015 | concepts TS | 概念库,用于优化编译期信息 |
2015 | TM TS | 事务性内存操作 |
2015 | parallelism TS | 用于并行计算的扩展 |
2015 | filesystem TS | 文件系统 |
2014 | C++14 | 第四个C++标准 |
2011 | - | 十进制浮点数扩展 |
2011 | C++11 | 第三个C++标准 |
2010 | - | 数学函数扩展 |
2007 | C++TR1 | C++技术报告:库扩展 |
2006 | - | C++性能技术报告 |
2003 | C++03 | 第二个C++标准 |
1998 | C++98 | 第一个C++标准 |
# 编译器安装
GNU 的 C/C++
Linux 或 UNIX 安装 GCC,按照 http://gcc.gnu.org/install/ (opens new window) 安装
Mac OS X,苹果系统的Xcode 会携带
Xcode 目前可从 developer.apple.com/technologies/tools/ (opens new window) 上下载
Windows 上安装 GCC,要安装 MinGW,请访问 MinGW 的主页 www.mingw.org (opens new window)
# Hello World
#include <iostream> // 引入支持输入输出的库
using namespace std; // 命名空间
int main(){ // 程序开始执行入口函数
cout << "Hello World"; // cout 输出
return 0;
}
# 编译 & 执行
1、将上面代码保存文件为 hello.cpp
2、gcc编译文件,并默认生成 a.out可执行文件
$ g++ hello.cpp
3、键入' a.out' 来运行程序
$ ./a.out
4、屏幕上显示
Hello World
也可以使用 makefile 来编译 C/C++ 程序
# 语句结束符
分号是语句结束符。
int a = 1;
# 代码块
块是一组使用大括号括起来的按逻辑连接的语句
{
cout << "Hello World"; // 输出 Hello World
return 0;
}
# 命名规范
标识符规范:
标识变量、函数、类、模块,或任何其他用户自定义项目的名称。
以字母 A-Z 或 a-z 或下划线 _ 开始,后跟零个或多个字母、下划线和数字(0-9)
不允许出现标点字符,比如 @、$ 和 %。
命名区分大小写
# 关键字
关键字,就是被系统占用的名称,需要取其它名称,避开它
asm | else | new | this |
---|---|---|---|
auto | enum | operator | throw |
bool | explicit | private | true |
break | export | protected | try |
case | extern | public | typedef |
catch | false | register | typeid |
char | float | reinterpret_cast | typename |
class | for | return | union |
const | friend | short | unsigned |
const_cast | goto | signed | using |
continue | if | sizeof | virtual |
default | inline | static | void |
delete | int | static_cast | volatile |
do | long | struct | wchar_t |
double | mutable | switch | while |
dynamic_cast | namespace | template |
# 三字符组
通过?? 加上符号来表示另一个符号,这很少有,通常编译器也不支持,g++支持但是会警告。
三字符组 | 替换 |
---|---|
??= | # |
??/ | \ |
??' | ^ |
??( | [ |
??) | ] |
??! | | |
??< | { |
??> | } |
??- | ~ |
假如开启了三字符编译,??= 字符串该如何表示? 使用 ??=
# 注释
三种注释区别:
#include <iostream>
using namespace std;
/* 注释
* 可以跨行
*/
int main()
{
/* 单行局部注释,后面代码有效 */ int a = 2;
// 输出 Hello World!( 后面所有代码都是注释范围 )
cout << "Hello World!";
return 0;
}
# 日期 & 时间
获取当前系统的日期和时间,包括本地时间和协调世界时(UTC)。
#include <iostream>
#include <ctime>
using namespace std;
int main(){
// 基于当前系统的当前日期/时间
time_t now = time(0);
cout << "1970年1月1日到目前经过的秒数:" << now << endl;
tm *ltm = localtime(&now);
// 输出 tm 结构的各个组成部分
cout << "年: "<< 1900 + ltm->tm_year << endl;
cout << "月: "<< 1 + ltm->tm_mon<< endl;
cout << "日: "<< ltm->tm_mday << endl;
cout << "时间: "<< 1 + ltm->tm_hour << ":";
cout << 1 + ltm->tm_min << ":";
cout << 1 + ltm->tm_sec << endl;
}
结果:
1970年1月1日到目前经过的秒数:1688304716
年: 2023
月: 7
日: 2
时间: 14:32:57
# 数据
# 数据类型
1、系统类型
类型 | 关键字 |
---|---|
布尔型 | bool |
字符型 | char |
整型 | int |
浮点型 | float |
双浮点型 | double |
无类型 | void |
宽字符型 | wchar_t |
2、基本类型修饰符:(可以使用一个或多个)
- signed
- unsigned
- short
- long
3、变量类型占用的内存(不同系统会有所差异)
类型 | 位 | 范围 |
---|---|---|
char | 1 个字节 | -128 到 127 或者 0 到 255 |
unsigned char | 1 个字节 | 0 到 255 |
signed char | 1 个字节 | -128 到 127 |
int | 4 个字节 | -2147483648 到 2147483647 |
unsigned int | 4 个字节 | 0 到 4294967295 |
signed int | 4 个字节 | -2147483648 到 2147483647 |
short int | 2 个字节 | -32768 到 32767 |
unsigned short int | 2 个字节 | 0 到 65,535 |
signed short int | 2 个字节 | -32768 到 32767 |
long int | 8 个字节 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
signed long int | 8 个字节 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
unsigned long int | 8 个字节 | 0 到 18,446,744,073,709,551,615 |
float | 4 个字节 | 精度型占4个字节(32位)内存空间,+/- 3.4e +/- 38 (~7 个数字) |
double | 8 个字节 | 双精度型占8 个字节(64位)内存空间,+/- 1.7e +/- 308(~15 个数字) |
long double | 16 个字节 | 长双精度型 16 个字节(128位)内存空间,可提供18-19位有效数字。 |
wchar_t | 2 或 4 个字节 | 1 个宽字符 |
sizeof:获取类型内存大小
#include <iostream>
using namespace std;
int main()
{
cout << "Size of char : " << sizeof(char) << endl;
cout << "Size of int : " << sizeof(int) << endl;
return 0;
}
# typedef 别名
使用 typedef 为一个已有的类型取一个新的名字(别名)
#include <iostream>
using namespace std;
int main()
{
typedef int count; // 取别名,下面可以用Count 替换 int
count min = 3;
cout << "min =" << min << endl;
return 0;
}
结果
min =3
# 枚举类型
#include <iostream>
using namespace std;
int main()
{
enum RGB {
red,
green,
blue
} rgb1, rgb2, rgb3;
rgb1 = red;
rgb2 = green;
rgb3 = blue;
cout << "RGB:" << rgb1 << endl;
cout << "RGB:" << rgb2 << endl;
cout << "RGB:" << rgb3 << endl;
return 0;
}
结果:
RGB:0
RGB:1
RGB:2
默认情况下,第一个枚举值为 0,第二个枚举值为 1,第三个枚举值为 2,以此递增。
可以尝试设置某个值
# 【变量、常量】
包括基础数据类型变量、枚举、指针、数组、引用、数据结构、类等等
未初始化阶段:
1、数据类型声明通常都是0
2、对象类型声明通常默认NULL
#include <iostream>
using namespace std;
// 变量声明:extern 关键字允许函数体外声明变量
extern int a, b;
// 函数声明
int func_area(int a, int b);
int main ()
{
// 变量定义, 此时变量还是0
int a, b;
// 实际初始化
a = 10;
b = 20;
cout << func_area(a, b) << endl ;
return 0;
}
// 函数定义(如果没有函数声明,那么文件上面的代码不能调用,通常函数编译时能读取上面的定义)
int func_area(int a, int b)
{
return a*b;
}
# 左值、右值
左值(Lvalues)和右值(Rvalues)
通常对象是左值,数据是右值
int a = 10; // a 是左值, 10 是右值
int b = a; // a 是右值
# 局部变量
在函数或一个代码块内部声明的变量,称为局部变量:
int main ()
{
// 局部变量声明
int a, b;
return 0;
}
# 全局变量
函数外部定义的变量(通常是在程序的头部),称为全局变量。
程序的整个生命周期内都是有效的。
全局变量可以被任何函数访问。
#include <iostream>
using namespace std;
// 全局变量
int g = 4;
void print_g() {
cout << "g=" << g << endl; // 取的是全局变量g,不可能访问main函数内的g变量,作用域限制的。
}
int main ()
{
// 局部变量
int g = 2;
print_g();
cout << "g=" << g << endl; // 取当前函数内的局部变量g
return 0;
}
结果
g=4
g=2
⚠️ 都是打印g 结果不一样,一个取的是全局变量g。一个取当前函数内的局部变量g
# 整数常量
常量:固定的值,又叫做字面量。
例:
85 // 十进制
0213 // 八进制
0x4b // 十六进制
30 // 整数
30u // 无符号整数
30l // 长整数
30ul // 无符号长整数
212 // 合法的
215u // 合法的
0xFeeL // 合法的
078 // 非法的:8 不是八进制的数字
032UU // 非法的:不能重复后缀
# 浮点常量
例:
3.14159 // 合法的
314159E-5L // 合法的
510E // 非法的:不完整的指数
210f // 非法的:没有小数或指数
.e55 // 非法的:缺少整数或分数
# 布尔常量
- true 值代表真(不是1)
- false 值代表假(不是0)
在Object-C中有值且非0表示真,否则都是假
Swift同C++,bool都是表示真假
# 字符常量
转义序列 | 含义 |
---|---|
\ | \ 字符(转义字符表示后面的内容特殊含义) |
' | ' 字符 |
" | " 字符 |
? | ? 字符 |
\a | 警报铃声 |
\b | 退格键 |
\f | 换页符 |
\n | 换行符 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ooo | 一到三位的八进制数 |
\xhh . . . | 一个或多个数字的十六进制数 |
# 字符串常量
下面这三种形式所显示的字符串是相同的:
#include <iostream>
using namespace std;
int main ()
{
string a = "hello, string";
string b = "hello, \
string";
string c ="hello" ", " "string";
cout << "字符串a=" << a << endl;
cout << "字符串b=" << b << endl;
cout << "字符串c=" << c << endl;
return 0;
}
结果:
字符串a=hello, string
字符串b=hello, string
字符串c=hello, string
# [#define] 预处理器
预处理#define : 定义常量的一种方式, 不可修改,不能使用变量
例:
#include <iostream>
using namespace std;
// 宏定义
#define kWidth 39
int main()
{
cout << kWidth;
return 0;
}
# const 常量
例:
#include <iostream>
using namespace std;
int main()
{
const int kWidth = 39; // 定义const常量,不可修改
cout << kWidth;
return 0;
}
⚠️
const常量,不可修改,否则 error: assignment of read-only variable ‘kWidth’
# 数据修饰符
1、数据类型修饰符可以限制数据类型的精度和符号
2、修饰符 signed、unsigned、long 和 short 可应用于整型,
3、signed 和 unsigned 可应用于字符型,
4、long 可应用于双精度型。
5、也可以双修饰
例如:unsigned long int。
6、特殊修饰
可以不写 int 而表示整型:只写单词 unsigned short 或 unsigned long,int 是隐含的
# 类型限定符
类型限定符提供了变量的额外信息。
限定符 | 含义 |
---|---|
const | 编译器开始就是固定的,不可修改 |
volatile | 修饰符 volatile 告诉编译器,变量的值不确定的(不会缓存,每次都会重新获取) |
restrict | 由 restrict 修饰的指针是唯一一种访问它所指向的对象的方式。只有 C99 增加了新的类型限定符 restrict。 |
# 存储类
存储类:限定变量/函数的范围(可见性)和生命周期。
# 存储修饰: auto
auto 存储类是所有局部变量默认的存储类,可以不记
{
int a;
auto int b;
}
# 存储修饰: register
通常定义存储在寄存器中,用于需要快速访问的变量
{
register int m;
}
# 存储修饰: static
static 修饰符也可以应用于局部(函数体内)、全局变量(当前文件内访问)。
static 修饰变量是被类共享的,多个对象,不同函数体内读取的都是同一份
# 存储修饰: extern
extern :
1、字面意思:外部链接的,也即是可供其他文件使用
2、存储类全局变量的引用,它是跨文件访问的,不只是当前文件访问
//file1
extern const int a = 88; //声明并定义拥有外部链接的全局常量a,供外部文件file2访问
//file2
extern const int a; //声明全局常量a, 但是定义是来自于file1或其他文件的,当前文件拿来使用
# 存储修饰: mutable
mutable :
1、表示修饰成员是可以修改的,通常需要和const(常量的)结合使用
2、仅适用于类的对象
3、通常使用场景:const 修饰的成员函数内修改的变量需要是mutable修饰的,否则编译错误(因为const修饰后,原本默认可修改的成员调用时都相当于被const修饰,除非显式mutable修饰)
4、const修饰成员函数
const修饰成员函数的时候,const需要放在成员函数的后面,不能放在一开始,,若是放在一开始的话,那么const修饰的是函数的返回值,而非是修饰成员函数了
(示例不是很恰当)
#include <iostream>
#include <ctime>
using namespace std;
class Person
{
public:
string name;
int borth_year;
mutable int age; // 年龄
// const修饰成员函数(非mutable修饰的成员均不能在此函数内存在修改行为)
void desc() const {
time_t curtime;
time(&curtime);
tm *nowtime = localtime(&curtime);
// 如果 age 没有mutable修饰,那么这里就会报错
age = 1900 + nowtime->tm_year - borth_year;
cout << "姓名:" << name <<endl;
cout << "年龄:" << age <<endl;
}
};
int main( )
{
Person person;
person.name = "小明";
person.borth_year = 2018;
person.desc();
return 0;
}
结果:
姓名:小明
年龄:5
上述示例中,const 成员函数中可以修改 mutable 修饰可变成员 age。
但是早先mutable 是不支持的,我们进行如下改造:
#include <iostream>
#include <ctime>
using namespace std;
class Person
{
public:
string name;
int borth_year;
Person(string n, int y);
int age() const { // const修饰成员函数
time_t curtime;
time(&curtime);
tm *nowtime = localtime(&curtime);
return 1900 + nowtime->tm_year - borth_year;
}
// const修饰成员函数
void desc() const {
cout << "姓名:" << name <<endl;
cout << "年龄:" << age() <<endl;
}
};
Person::Person(string n, int y) {
name = n;
borth_year = y;
}
int main( )
{
Person person("小树", 2018);
person.desc();
return 0;
}
结果:
姓名:小树
年龄:5
# 数据运算
不同数据类型,不同系统,以及相同系统下不同算法优化 下所占用的内存大小均可能不相同
# 数据占用大小
常见数据类型不同系统内存大小:
数据类型 | 16位系统(占字节数) | 32位系统(占字节数) | 64位系统(占字节数) |
---|---|---|---|
char | 1(个字节,下同) | 1 | 1 |
short | 2 | 2 | 2 |
int | 2 | 4 | 4 |
unsigned int | 2 | 4 | 4 |
float | 4 | 4 | 4 |
double | 8 | 8 | 8 |
long | 4 | 4 | 8 |
long long | 8 | 8 | 8 |
unsigned long | 4 | 4 | 8 |
指针 | 2 | 4 | 8 |
最大数据范围 | 2^16 | 2^32 | 2^64 |
# 字节、字、位、比特
1字母a = 1 byte = 8 bit = 8 位二进制数
1 汉字 = 2 个字节byte = 16 字节bit(2*8) = 16 位二进制数
# 1、位
计算机都是二进制数,由0和1表示
1001 为4位
# 2、比特(bit)
表示二进制位的单位
1001 为4 bit
# 3、字节(byte)
字节(byte)是组成文字和字母的单位
1 byte = 8 bit = 8 位二进制数
# 4、字
比如汉字 “中国” 包含两个字,一个字占两个 “字节 ”, “中国” 字符串占 4个字节
比如字母 “abc” 占3个字节,也就是每个字母占一个字节
1字母a = 1 byte = 8 bit = 8 位二进制数
1 汉字 = 2 个字节byte = 16 字节bit(2*8) = 16 位二进制数
# 5、字块(连续的字)
多个文字或者字母等组成的内容为一个字块
比如磁道上的字群就称为一个字块。在磁带上通常每120个字符就间隔一个字块际志,也称为一个字块
# 6、字长(长度度量)
“中国” 两个字,
字节(byte)为度量单位时,字长为4个字节的长度
比特(bit)为度量单位时,字长为4*8=32个 bit的长度
# 【运算符】
# 运算符:算术
算术运算符:
运算符 | 描述 | 实例 |
---|---|---|
+ | 把两个操作数相加 | A + B |
- | 从第一个操作数中减去第二个操作数 | A - B |
* | 把两个操作数相乘 | A * B |
/ | 分子除以分母 | B / A |
% | 取模运算符,整除后的余数 | B % A |
++ | 自增运算符,整数值增加 1 | A++ |
-- | 自减运算符,整数值减少 1 | A-- |
# 运算符:关系
关系运算符:
运算符 | 描述 | 实例 |
---|---|---|
== | 值相等则条件为真,否则假 | (A == B) |
!= | 值不相等则条件为真,否则假 | (A != B) |
> | 值大于则条件为真,否则假 | (A > B) |
< | 值小于则条件为真,否则假 | (A < B) |
>= | 值大于或等于则条件为真,否则假 | (A >= B) |
<= | 值小于或等于则条件为真,否则假 | (A <= B) |
# 运算符:逻辑
关系逻辑运算符:
运算符 | 描述 | 实例 |
---|---|---|
&& | 左右均为真,则条件为真。 | (A && B) |
|| | 左右至少一个为真,则条件为真 | (A || B) |
! | 取反 | !A |
# 运算符:位运算
位运算符(二进制操作):
运算符 | 描述 | 实例 |
---|---|---|
& | 同位数操作,都是1计算为1,否则0 | 101 & 11 = 101 |
| | 同位数操作,至少一个1,则1 | 10 | 11 = 11 |
^ | 不相同的值为1,相同为0 | 1^1=0;0^1=1;1^0=1;0^0=0 |
~ | 二进制取反运算符:"翻转"位效果,依赖数据类型 | ~ 0010 = 1101 |
<< | 二进制左移运算符 | 11 << 2 为 1100 |
>> | 二进制右移运算符 | 11 >> 2 为 0 |
位运算符作用于位,并逐位执行操作。&、 | 和 ^ 的真值表如下所示:
p | q | p & q | p | q | p ^ q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
# 运算符:赋值
下表列出了 C++ 支持的赋值运算符:
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,把右边操作数的值赋给左边操作数 | C = A + B 将把 A + B 的值赋给 C |
+= | 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 | C += A 相当于 C = C + A |
-= | 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 | C -= A 相当于 C = C - A |
*= | 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 | C *= A 相当于 C = C * A |
/= | 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 | C /= A 相当于 C = C / A |
%= | 求模且赋值运算符,求两个操作数的模赋值给左边操作数 | C %= A 相当于 C = C % A |
<<= | 左移且赋值运算符 | C <<= 2 等同于 C = C << 2 |
>>= | 右移且赋值运算符 | C >>= 2 等同于 C = C >> 2 |
&= | 按位与且赋值运算符 | C &= 2 等同于 C = C & 2 |
^= | 按位异或且赋值运算符 | C ^= 2 等同于 C = C ^ 2 |
|= | 按位或且赋值运算符 | C |= 2 等同于 C = C | 2 |
请看下面的实例,了解 C++ 中所有可用的赋值运算符。
复制并黏贴下面的 C++ 程序到 test.cpp 文件中,编译并运行程序。
#include <iostream>
using namespace std;
int main()
{
int a = 21;
int c ;
c = a;
cout << "Line 1 - = 运算符实例,c 的值 = : " <<c<< endl ;
c += a;
cout << "Line 2 - += 运算符实例,c 的值 = : " <<c<< endl ;
c -= a;
cout << "Line 3 - -= 运算符实例,c 的值 = : " <<c<< endl ;
c *= a;
cout << "Line 4 - *= 运算符实例,c 的值 = : " <<c<< endl ;
c /= a;
cout << "Line 5 - /= 运算符实例,c 的值 = : " <<c<< endl ;
c = 200;
c %= a;
cout << "Line 6 - %= 运算符实例,c 的值 = : " <<c<< endl ;
c <<= 2;
cout << "Line 7 - <<= 运算符实例,c 的值 = : " <<c<< endl ;
c >>= 2;
cout << "Line 8 - >>= 运算符实例,c 的值 = : " <<c<< endl ;
c &= 2;
cout << "Line 9 - &= 运算符实例,c 的值 = : " <<c<< endl ;
c ^= 2;
cout << "Line 10 - ^= 运算符实例,c 的值 = : " <<c<< endl ;
c |= 2;
cout << "Line 11 - |= 运算符实例,c 的值 = : " <<c<< endl ;
return 0;
}
尝试一下
当上面的代码被编译和执行时,它会产生下列结果:
Line 1 - = 运算符实例,c 的值 = 21
Line 2 - += 运算符实例,c 的值 = 42
Line 3 - -= 运算符实例,c 的值 = 21
Line 4 - *= 运算符实例,c 的值 = 441
Line 5 - /= 运算符实例,c 的值 = 21
Line 6 - %= 运算符实例,c 的值 = 11
Line 7 - <<= 运算符实例,c 的值 = 44 Line 8 - >>= 运算符实例,c 的值 = 11
Line 9 - &= 运算符实例,c 的值 = 2
Line 10 - ^= 运算符实例,c 的值 = 0
Line 11 - |= 运算符实例,c 的值 = 2
# 运算符:其他
下表列出了 C++ 支持的其他一些重要的运算符。
运算符 | 描述 |
---|---|
sizeof | sizeof 运算符 (opens new window)返回变量的大小。例如,sizeof(a) 将返回 4,其中 a 是整数。 |
Condition ? X : Y | 条件运算符 (opens new window)。如果 Condition 为真 ? 则值为 X : 否则值为 Y。 |
, | 逗号运算符 (opens new window)会顺序执行一系列运算。整个逗号表达式的值是以逗号分隔的列表中的最后一个表达式的值。 |
.(点)和 ->(箭头) | 成员运算符 (opens new window)用于引用类、结构和共用体的成员。 |
Cast | 强制转换运算符 (opens new window)把一种数据类型转换为另一种数据类型。例如,int(2.2000) 将返回 2。 |
& | 指针运算符 & (opens new window) 返回变量的地址。例如 &a; 将给出变量的实际地址。 |
* | 指针运算符 * (opens new window) 指向一个变量。例如,*var; 将指向变量 var。 |
# 运算符:优先级
运算符的优先级确定表达式中项的组合。这会影响到一个表达式如何计算。某些运算符比其他运算符有更高的优先级,例如,乘除运算符具有比加减运算符更高的优先级。
例如 x = 7 + 3 * 2,在这里,x 被赋值为 13,而不是 20,因为运算符 * 具有比 + 更高的优先级,所以首先计算乘法 3*2,然后再加上 7。
下表将按运算符优先级从高到低列出各个运算符,具有较高优先级的运算符出现在表格的上面,具有较低优先级的运算符出现在表格的下面。在表达式中,较高优先级的运算符会优先被计算。
类别 | 运算符 | 结合性 |
---|---|---|
后缀 | () [] -> . ++ - - | 从左到右 |
一元 | + - ! ~ ++ - - (type)* & sizeof | 从右到左 |
乘除 | * / % | 从左到右 |
加减 | + - | 从左到右 |
移位 | << >> | 从左到右 |
关系 | < <= > >= | 从左到右 |
相等 | == != | 从左到右 |
位与 AND | & | 从左到右 |
位异或 XOR | ^ | 从左到右 |
位或 OR | | | 从左到右 |
逻辑与 AND | && | 从左到右 |
逻辑或 OR | || | 从左到右 |
条件 | ?: | 从右到左 |
赋值 | = += -= *= /= %=>>= <<= &= ^= |= | 从右到左 |
逗号 | , | 从左到右 |
请看下面的实例,了解 C++ 中运算符的优先级。
复制并黏贴下面的 C++ 程序到 test.cpp 文件中,编译并运行程序。
对比有括号和没有括号时的区别,这将产生不同的结果。因为 ()、 /、 * 和 + 有不同的优先级,高优先级的操作符将优先计算。
#include <iostream>
using namespace std;
int main()
{
int a = 20;
int b = 10;
int c = 15;
int d = 5;
int e;
e = (a + b) * c / d; // ( 30 * 15 ) / 5
cout << "(a + b) * c / d 的值是 " << e << endl ;
e = ((a + b) * c) / d; // (30 * 15 ) / 5
cout << "((a + b) * c) / d 的值是 " << e << endl ;
e = (a + b) * (c / d); // (30) * (15/5)
cout << "(a + b) * (c / d) 的值是 " << e << endl ;
e = a + (b * c) / d; // 20 + (150/5)
cout << "a + (b * c) / d 的值是 " << e << endl ;
return 0;
}
尝试一下
当上面的代码被编译和执行时,它会产生下列结果:
(a + b) * c / d 的值是 90
((a + b) * c) / d 的值是 90
(a + b) * (c / d) 的值是 90
a + (b * c) / d 的值是 50
# 【运算逻辑】
# 运算:原码、反码、补码
计算机是二进制计算,严格说没有减法的说法,只有加法,都是采用补码进行运算
1、数据类型
数据操作前提,首先明确一点是数据类型, 不同类型数据内存空间大小不一样
2、高位为符号位
第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是:
[1111 1111 , 0111 1111]
也就是[-127,127];
第一位是1代表负数,第一位0代表正数
3、负数
原码、反码、补码 是相对于负数来说的,正数都是相同的
# 运算:正、负
正数:原码=反码=补码
int a = 5;
原码:0000 0101
反码:0000 0101
补码:0000 0101
三者相同
负数:
原码=正数原码最高位变1
反码=原码(除符号位)都取反,
补码=反码+1
int a = -5;
原码:1000 0101 // 正数5原码最高位变1
反码:1111 1010 // 原码(除符号位)都取反
补码:1111 1011 // 反码+1
# 运算:加、减
运算:
【补码 + 补码 】的形式进行的
1、加法
5 + 5 = 10;
5补码:0000 0101
+
5补码:0000 0101
=
结果:0000 1010
2、减法
5 - 5
= 5 + (-5)
= 0;
5补码:0000 0101
+
-5补码:1111 1011
=
结果:1000 0000
= -0 = 0
(-0 也就是0, 虽然二进制不一样,但是数据一样)