C++自学 | 1 概述 & 数据类型 & 变量

本内容仅属于个人自学记录,欢迎交流和指正,请勿转载或发表不当言论。

主要学习网址:https://www.runoob.com/


1.1 Cplus/C++ 简介

 

1.  定义:C++ 是一种静态类型的[1]、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化编程、面向对象编程[2]和泛型编程。它被认为是一种中级语言。

2.  区分:C++ 是 C 的一个超集,事实上,任何合法的 C 程序都是合法的 C++ 程序。

[1]:使用静态类型的编程语言是在编译时执行类型检查,动态类型的编程语言则是在运行时执行类型检查。

参考:https://blog.csdn.net/aiming66/article/details/78570784

[2]:面向对象开发的四大特点:封装,抽象,继承,多态。

3.  文件扩展名:.c /.cp /.cpp

 

 

 


1.2 Cplus/C++ 基本语法

 

1.  概括:C++可以定义为对象的集合,对象之间通过调用进行彼此交互。

  • 对象:类的实例。
  • 类:描述对象行为/状态的模板。
  • 方法:一个类可以包含多个方法,方法中写入逻辑,操作数据及执行的动作。
  • 即时变量:对象中的独特变量,创建并代表了对象的状态。

2.  标识符:不允许出现标点字符(@,&,%等)但可以出现 $

3.  关键字:C++98/03中包含63个关键字,C++11中包含73个,新增10个。

关键字详解:https://www.cnblogs.com/ybChen/p/12728240.html

 

4.  注释方法:

两种注释可互相嵌套,但是不可嵌套代码:

1 // 这是一行注释
2  
3  /* 这是可跨行注释 */

可嵌套代码的注释:

 1 //Eg:如果condtion的条件为true,执行code1,否则执行code2。
 2 
 3  #if condition
 4     code 1
 5  #else
 6     code2
 7  #endif
 8 
 9 //注释代码
10 #if 0
11     code
12 #end13 
14 //执行代码
15 #if 1
16     code
17 #end

 

 

 


1.3 C++的数据类型

 

小结:

C++共有7个基本数据类型,4个类型修饰符,可通过不同的组合得到不同长度的数据类型。此外,枚举类型(enumeration)是C++中派生出来的一种数据类型,其首先定义一个数据集,该类型变量的取值只能在对应的数据集中选择。

此外,我们可以用typedef或#define为变量取别名,但要注意两者之间的差异。

 

1.  内置数据类型:有7个基本类型,4个类型修饰符(signed, unsigned, short, long)

基本类型 描述
void 表示类型的缺失
bool true or false
char 一个整数类型。
int 机器整数的最自然大小。
float

单精度浮点值,格式为:1位符号,8位指数,23位小数。

double

双精度浮点值,格式为:1位符号,11位指数,52位小数。

wchar_t  

各种组合的变量类型在存储时占用的内存,及其取值范围。

类型 范围
void 0 byte 无值域
bool 1 byte true or false
char 1 byte -128 到 127 或者 0 到 255
unsigned char 1 byte 0 到 255
signed char 1 byte -128 到 127
int 4 byte -2147483648 到 2147483647
unsigned int 4 byte 0 到 4294967295
signed int 4 byte -2147483648 到 2147483647
short int 2 byte -32768 到 32767
unsigned short int 2 byte 0 到 65,535
signed short int 2 byte -32768 到 32767
long int 8 byte -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
signed long int 8 byte -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
unsigned long int 8 byte 0 到 18,446,744,073,709,551,615
float 4 byte

精度型占4个byte(32位)内存空间

+/- 3.4e +/- 38 (~7 个数字)

double 8 byte

双精度型占8 个byte(64位)内存空间

+/- 1.7e +/- 308 (~15 个数字)

long double 16 byte

长双精度型 16 个byte(128位)内存空间

可提供18-19位有效数字。

wchar_t(宽字符型) 2 或 4 byte 1 个宽字符
 
宽字符的定义:
typedef short int wchar_t;   //占用空间类似short int

 

2.  新定义:typedef

  • 声明:为一个已有类型取新的名字

例如:

typedef type newname;

//Example
typedef int feet;
feet distance;  //distance是一个int类型的变量。
  • 与#define的区别:

1)执行时间:

typedef:在编译阶段有效,因此有类型检查的功能。

#define:发生在预处理阶段,只进行简单的字符串替换,不进行检查。

2)功能:

typedef:定义类型别名,定义与平台无关的数据类型。

#define:定义类型别名,定义常量,变量,编译开关。 

3)作用域:

typedef:有作用域的限制,一般为局部使用,在类中用typedef定义的类型别名有相应的访问权限。

【例如:

class A
{
    typedef unsigned int UINT;
    UINT valueA;
    A() : valueA(0){}
};
 
void func3()
{
    A::UINT i = 1;
    // error C2248: 'A::UINT' : cannot access private typedef declared in class 'A'
}

【修正:

class A
{
public:   //增加了public访问权限
    typedef unsigned int UINT;
    UINT valueA;
    A() : valueA(0){}
};
 
void func3()
{
    A::UINT i = 1;
    cout << i << endl;
}

#define:没有作用域的限制,只要预定义过可以在全局使用。

 

  

3.  枚举类型(enumeration)

  • 概念:C++中一种派生数据类型,是由用户定义的若干枚举常量的集合。定义的这个变量的值只能在列举出来的值的范围内。
  • 形式:
enum 枚举名{ 
     标识符[=整型常数], 
     标识符[=整型常数], 
... 
    标识符[=整型常数]
} 枚举变量;

【实例:

//未初始化枚举值:从左至右被分配一个整型值,默认从0开始逐个增加1,
enum color {red, green, blue} c;
c = blue;
//变量c的类型名为 color,赋值为 blue,整型常数为2。


//初始化枚举值:
enum color{red, green = 5, blue};
enum color c = blue;
//变量c的类型为 color,赋值为 blue,整型常数为6。
//c只能取枚举变量color集合内的值,默认情况下每个名称都会比前面的名称数值大1,但red = 0。

 

 

 

 


1.4 Cplus/C++的变量类型

 

小结:

在某个具体部分,变量只能被定义一次,但可以被多此声明(extern)。此外,变量依据不同的作用域和内存空间分配方式,总共可分为静态全局变量(静态存储,全局作用域,特定文件作用域),静态局部变量(静态存储,局部作用域),非静态全局变量(静态存储,全局作用域),非静态局部变量(栈内分配,局部作用域)(仅在函数执行期间存在)几种,在使用中可能会依照需求进行调整。

 

1.  变量定义:

为某个类型一个变量,并分配相应的存储空间。

有效的定义实例:

extern int a = 3, b = 6;  //声明同时定义,并分配存储空间
int a = 3, b = 6;

 

2.  变量声明:

不带初始化的定义中,带有静态存储持续时间的变量会被隐式初始化为NULL(所有字节为0),其他所有变量的初始值都是未定义的。

extern 关键字可以在任何地方声明一个变量,变量可以多次声明,但只能在某个具体部位被定义一次。

任何在多个文件中使用的变量都需要有与定义分离的声明。

实例:

extern int a, b;  //仅说明存在变量a,b,具体定义需要编译器在代码中寻找。

 

3.  函数声明:

在代码开始部分声明一个函数,提供函数名,而其实际定义可以在任何地方进行。

// 函数声明
int func();
 
int main()
{
    // 函数调用
    int i = func();
}
 
// 函数定义
int func()
{
    return 0;
}

C/C++ 编译 cpp 文件是从上往下编译,所以 main 函数里面调用其他函数时,如果其他函数在 main 函数的下面,则要在 main 函数上面先声明这个函数。

或者把 main 函数放在最下面,这个不仅限于 main 函数,其他函数的调用都是如此。被调用的函数要在调用的函数之前声明。

 

4.  变量分类:

>>>按照变量作用域分类,可以将变量分为三类:

变量分类 作用域 备注
局部变量 在函数或一个代码内部声明的变量。
【例】

#include<iostream> using namespace std; int main() { //局部变量声明 int a, b; //局部变量初始化 a = 10; b = 20; return 0; }

 

形式参数 在函数参数的定义中声明的变量。  
全局变量 在所有函数外部声明的变量。 可以被任何函数访问,在整个程序中都可用。

 

系统不会为定义的局部变量进行初始化,但会为定义的全局变量初始化为下列值:

数据类型初始化默认值
int 0
char '\0'
float 0
double 0
pointer NULL

备注:

字符’0‘:char c = ’0‘  其ASCII码为48,内存中的表现形式是00110000。

字符’\0‘:转椅字符,ASCII码为0,是一个字符串结束的标志,内存中的表现形式是00000000。

整数0: 内存中表示为 00000000 00000000 00000000 00000000,占用长度不同。

 

局部变量的名称可以与全局变量相同,但是在具体函数或代码块内部,局部变量的值会覆盖全局变量的值。如有需要,可通过域名在函数中引用到全局变量,不加域名解析则引用局部变量。

#include<iostream>
using namespace std;

int a = 10;
int main()
{
    int a = 20;
    cout << ::a << endl;   // 10
    cout << a << endl;     // 20
    return 0;
}

 

增加static后的静态变量:

  • 静态局部变量:拥有局部作用域,只被初始化一次,自从第一次被初始化后直到程序运行结束一直都存在,只对定义自己的函数体可见。
  • 静态全局变量:拥有全局作用域,只作用于定义自己的文件,无法被其他文件调用,也可称为拥有文件作用域。

 

>>>按照变量分配内存空间分类,可以将变量分为两类:

变量分类 存储方式 备注
静态变量 在程序的静态数据存储区(数据段),全局可见。 全局变量本身是静态存储方式,但作用域与静态全局变量有所不同。
局部变量 在栈中分配空间。  

注:把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。应予以注意。

 

 


1.5 Cplus/C++的常量

 

小结:

常量分为整数常量,浮点常量,布尔常量,字符常量,字符串常量五种,其可以通过#define和const来进行定义。 

 

常量又叫字面量,是程序执行期间不会改变的固定值。

1.  整数常量

//整数常量后缀:U/u无符号整数(unsigned),L/l长整数(long)

// 无前缀默认为十进制
6918               //合法十进制
6918u              //合法十进制,无符号整数
6918uL             //合法十进制,无符号长整数

//0前缀表示八进制
077                //合法八进制
078                //非法八进制

//0X或0x表示十六进制
0X4b              //合法十六进制
0xFeeL            //合法十六进制,长整数

 

2.  浮点常量:

包括整数部分,小数点,小数部分和指数部分。

//小数形式必须包含整数,小数,或同时包含两者
//指数形式必须包含小数点,指数,或同时包含两者

3.1415926        //合法
31415926E-7      //合法
510E             //非法,不完整指数
210f             //非法,没有小数或指数
.e55             //非法,缺少整数或分数

 

3.  布尔常量:

只有true和false两个,是C++关键字。

 

4.  字符常量:

如果常量以且仅以L开头时,则该字符常量是一个宽字符常量,必须存储在wchar_t类型变量中。

wchar_t c = L'x';

否则就是一个窄字符常量,可以存储在char类型变量中。

char c = 'x';

 

转义序列含义
\\ \ 字符
\' ' 字符
\" " 字符
\? ? 字符
\a 警报铃声
\b 退格键
\f 换页符
\n 换行符
\r 回车
\t 水平制表符
\v 垂直制表符
\ooo 一到三位的八进制数
\xhh . . . 一个或多个数字的十六进制数

 

5.  字符串常量:

代码实例:

//三种形式的输出结果相同
"hello, dear"


"hello, \

dear"


"hello, " "d" "ear"

 

6.  定义常量:(一般常量都为大写字母形式)

1)使用#define预处理器:

#define identifier value  //宏定义常量
#undef identifier value //取消宏定义
  • 宏定义是字符替换,没有数据类型的区别,同时这种替换没有类型安全检查,可能产生边际效应等错误;
  • 宏定义在预处理阶段展开,不会进行测试;
  • 直接进行替换,不会分配内存,存储在程序的代码段中;
  • 宏定义可以在全局使用;
  • 不能作为参数传递给函数。

注:#define为变量定义后,不能使用分号结束语句,否则会出现计算错误,但程序不会报错。

#define age  12
#define age1 10

#define age2  12;
#define age3 10;

 

int main()
{
   int dd  ; 
   dd = age + age1;
   cout  << "值=" << dd << endl; //值22
   dd = age2 + age3;
   cout  << "值=" << dd << endl; //值12
    return 0;  
}

 

2)使用const关键字

const type variable = value;
  • const常量是一种常量的声明,有类型区别,因此编译阶段会进行类型检查;
  • 定义后的const常量,在编译运行中使用,在后续程序中为只读模式;
  • const常量需要进行内存分配,存储在程序的数据段中;
  • const常量只能在定义它的函数或代码段中使用;
  • 可以在函数的参数列表中出现。

 

 


 

 1.6 Cplus/C++ 修饰符类型

 

1.  修饰符:

允许在char,int,double数据类型前添加修饰符,用于改变基本类型的含义,如没有 signed/unsigned 缀修饰符,则默认为有符号 signed 整数。

修饰符 修饰类型
signed int,char,short,long
unsigned int,char,short,long
long int,double
short int,double

速记符号也可以用来声明无符号短整数或无符号长整数,例如以下语句都可以声明无符号整型变量。

unsigned x;        //int省略
unsigned int x;   

有符号整数在二进制中,最左边一位的补码是1,代表负数。

对于无符号化为有符号的位数运算,采用 N-2^n 计算,N为无符号数的数值,n取决于定义的数据类型。

 

 2.  类型限定符

限定符含义扩展
const const 类型的对象在程序执行期间不能被修改改变。  
volatile 修饰符 volatile 告诉编译器不需要优化volatile声明的变量,让程序可以直接从内存中读取变量。对于一般的变量编译器会对变量进行优化,将内存中的变量值放在寄存器中以加快读写效率。

往往用于多线程的修饰,以保证另一线程在调用相关变量时每次都从内存中读取对应值。

restrict 由 restrict 修饰的指针是唯一一种访问它所指向的对象的方式。只有 C99 增加了新的类型限定符 restrict。  

 

 


 

1.7 Cplus/C++存储类

 

存储类定义了C++程序中变量/函数的范围(可见性)和生命周期,这些说明符一般添加在它们所修饰的类型之前。

  • auto
  • register
  • static
  • extern
  • mutable
  • thread_local(C++11)

从C++17开始,auto关键字不再是存储类说明符,且register关键字被弃用。

 

1.  auto存储类:

自C++11以来应用于两种情况:

  • 声明变量时根据初始化表达式自动推断该变量类型。
  • 声明函数时函数返回值的占位符
//第一种情况示例
auto f=3.14;             //double
auto s("hello");         //const char*
auto z = new auto(9);    //int*

auto x1 = 5, x2 = 5.0, x3 = 'r';  //非法,变量必须初始化为同类型。

 

2.  register存储类

用于定义存储在寄存器中而不是RAM的局部变量,其最大尺寸等于寄存器的大小(通常是一个词),且不能对它使用一元的 & 运算符(因为没有内存位置)。

寄存器只用于需要快速访问的变量,例如计数器。

使用register以为着变量可能存储在寄存器中,这取决于硬件和实现的限制。

 

3.  static存储类

指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。

在修饰局部变量时,可以在函数调用之间保持局部变量的值。

在修饰全局变量时,会将变量的作用域限制在声明它的文件内。

在修饰类数据成员时,会导致仅有一个该成员的副本被类的所有对象共享。

 

4.  extern存储类

用于提供一个全局变量的引用,在同一个程序的另一个文件中声明一个全局变量或函数,当使用extern时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。

 

5.  mutable存储类

仅适用于类的对象,允许对象成员代替常量。

mutable成员可以通过const成员函数修改。

 

6.  thread_local存储类

该说明符声明的变量仅可在创建它的线程上访问,变量在线程创建时创建,并随线程销毁而销毁,每个线程都有自己的变量副本。

可以被声明为 thread_local 的变量:

thread_local int x;  // 命名空间下的全局变量
class X
{
    static thread_local std::string s; // 类的static成员变量
};
static thread_local std::string X::s;  // X::s 是需要定义的
 
void foo()
{
    thread_local std::vector<int> v;  // 本地变量
}

std(standard) 是标准库函数使用的命名空间,预处理 using namespace std 声明了命名空间std,后续如果有未指定命名空间的符号,则默认使用std。如果不用预处理,就要加上 std::cin     std::cout

cin>>   //输入对象,用于从控制台获取用户输入
cout<<  //输出流对象,用于将数据输出到控制台

 

 


 

 1.8 Cplus/C++运算符

 

1.  算术运算符:

运算符描述备注
+ 把两个操作数相加  
- 从第一个操作数中减去第二个操作数  
* 把两个操作数相乘  
/ 分子除以分母

整数运算会取整数结果。

例:21/10 编译结果为 2

% 取模运算符,整除后的余数  
++ 自增运算符,整数值增加 1

前缀:++x 先对x值+1再使用x执行命令

后缀:x++ 先使用x执行命令再对x值+1

-- 自减运算符,整数值减少 1  

/ 和 % 运算中,若两个操作数是正数,则除法的结果是正数,求模的结果也是正数;

若两个操作数是负数,则除法的结果是正数,求模的结果是负数;

若一正一负,则除法的结果是负数,求模的结果取决于机器。 

 

2.  关系运算符:

运算符描述实例
== 检查两个操作数的值是否相等,如果相等则条件为真。 (A == B) 不为真。
!= 检查两个操作数的值是否相等,如果不相等则条件为真。 (A != B) 为真。
> 检查左操作数的值是否大于右操作数的值,如果是则条件为真。 (A > B) 不为真。
< 检查左操作数的值是否小于右操作数的值,如果是则条件为真。 (A < B) 为真。
>= 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 (A >= B) 不为真。
<= 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 (A <= B) 为真。

 

 3.  逻辑运算符:

运算符描述实例(A=1;B=0)
&&

称为逻辑与运算符。如果两个操作数都非零,则条件为真。

(A && B) 为假。
|| 称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。 (A || B) 为真。
! 称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。 !(A && B) 为真。

 技巧:

1.  &&会先判断左边的值是否为真,若为真则继续判断右边。这时可以判断右值的过程相当于if条件句。

/*不用任何循环语句,不用if,来实现1+2+3+...+10的值*/
#include <iostream>
using namespace std;

int add(int c)
{
    int a=0;
    c&&(a=add(c-1));//递归循环,直到传入c的值为0则结束循环
    cout<<c+a<<endl;
    return c+a;
}
int main()
{ 
    add(10);
    return 0;
}

2.  || 会先判断左值的真假,若左值为真,则不会再计算右边的值.

上述实例中的递归循环可以改成:

(!c)||(a=add(c-1));

 

4.  位运算符:

位运算符作用于位,并且逐位执行,一般以二进制的形式进行计算,默认输出结果仍为十进制。

运算符描述实例
& 如果同时存在于两个操作数中,二进制 AND 运算符复制一位到结果中。
pqp & qp | qp ^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1
| 如果存在于任一操作数中,二进制 OR 运算符复制一位到结果中。
^ 如果存在于其中一个操作数中但不同时存在于两个操作数中,二进制异或运算符复制一位到结果中。
~ 二进制补码运算符是一元运算符,具有"翻转"位效果,即0变成1,1变成0。
<<

二进制左移运算符。左操作数的值向左 移动 右操作数 指定的位数。

(将开头两位去掉)在尾端加位00。

107(0000 0110 1011)<<2

编译结果为428(0001 1010 1100)

>>

二进制右移运算符。左操作数的值向右 移动 右操作数 指定的位数。

把尾数去掉。

158(10011001)>>2

编译结果为38 (100110)


 5.  赋值运算符:

 

运算符描述实例
= 简单的赋值运算符,把右边操作数的值赋给左边操作数 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

多个赋值操作中,各对象必须具有相同的数据类型,或者具有可转换为同类型的数据类型。

//非法实例
int i;
int *ip;
i = ip = 0;  //error,虽然两者都可以赋值为0

 

 

 

 6.  其他运算符:

下表举例列出了一些重要的运算符:

运算符描述
sizeof sizeof 运算符返回变量的大小。例如,sizeof(a) 将返回 4,其中 a 是整数。
Condition ? X : Y 条件运算符。如果 Condition 为真 ? 则值为 X : 否则值为 Y。
,

逗号运算符会顺序执行一系列运算。整个逗号表达式的值是以逗号分隔的列表中的最后一个表达式的值。

var = (express1, express2, express3);
//先求解表达式1,再求解表达式2,3,整个逗号表达式的值是最右边表达式的值,其他值会被丢弃。

 

.(点)和 ->(箭头)

成员运算符用于引用类、结构和共用体的成员。

点运算符应用于实际的对象。箭头运算符与一个指向对象的指针一起使用。

例如假设有如下结构体:

struct Employee{
    char first_name[16];
    int age;
} emp;

点运算符的赋值:

strcpy(emp.first_name, "zara");
//将zara赋值给对象emp的成员first_name

箭头运算符的赋值:

strcpy(p_emp->first_name, "zara");
//同样将zara赋值。
//p_emp是一个指向类型为Employee的对象。
Cast 强制转换运算符把一种数据类型转换为另一种数据类型。例如,int(2.2000) 将返回 2。
& 指针运算符 & 返回变量的地址。例如 &a; 将给出变量的实际地址。
* 指针运算符 * 指向一个变量。例如,*var; 将指向变量 var。

 

有时可能会见到 --> 但其实是 -- 和 > 两个操作符。

while(x --> 0)
//先进行x与0的比较,返回结果再进行自减运算。

 

 

 

7.  强制转换运算符:

一般为(type)expression,以下列出了C++支持的几种:

  • const_cast<type> (expr): const_cast 运算符用于修改类型的 const / volatile 属性。除了 const 或 volatile 属性之外,目标类型必须与源类型相同。这种类型的转换主要是用来操作所传对象的 const 属性,可以加上 const 属性,也可以去掉 const 属性。

  • dynamic_cast<type> (expr): dynamic_cast 在运行时执行转换,验证转换的有效性。如果转换未执行,则转换失败,表达式 expr 被判定为 null。dynamic_cast 执行动态转换时,type 必须是类的指针、类的引用或者 void*,如果 type 是类指针类型,那么 expr 也必须是一个指针,如果 type 是一个引用,那个 expr 也必须是一个引用。

  • reinterpret_cast<type> (expr): reinterpret_cast 运算符把某种指针改为其他类型的指针。它可以把一个指针转换为一个整数,也可以把一个整数转换为一个指针。

  • static_cast<type> (expr): static_cast 运算符执行非动态转换,没有运行时类检查来保证转换的安全性。例如,它可以用来把一个基类指针转换为派生类指针。

 

8.  运算符优先级:

类别 运算符 结合性 
后缀  () [] -> . ++ - -   从左到右 
一元  + - ! ~ ++ - - (type)* & sizeof  从右到左 
乘除  * / %  从左到右 
加减  + -  从左到右 
移位  << >>  从左到右 
关系  < <= > >=  从左到右 
相等  == !=  从左到右 
位与 AND  从左到右 
位异或 XOR  从左到右 
位或 OR  从左到右 
逻辑与 AND  &&  从左到右 
逻辑或 OR  ||  从左到右 
条件  ?:  从右到左 
赋值  = += -= *= /= %=>>= <<= &= ^= |=  从右到左 
逗号  从左到右 

 

 

 

 

 

 

 

 

 

 

posted @ 2020-06-08 00:51  伏延  阅读(331)  评论(0编辑  收藏  举报