C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++变量和基本类型

C++变量和基本类型详解

作者:Binary_of

这篇文章主要介绍了C++变量和基本类型,,一定要注意局部变量与全局变量的作用范围,需要的朋友可以参考下,希望能够给你带来帮助

基本内置类型

算术类型分为两类:整型(包括字符和布尔类型在内)和浮点型

1. 不同平台下基本类型的字节数

类型 16位平台 32位平台 64位平台
char 1 1 1
short 2 2 2
int 2 4 4
long 4 4 8
long long / 8 8
指针 2 4 8
float 4 4 4
double 8 8 8

数据类型long long 是在C++11中新定义的。

2. 算数类型的最小尺寸

算术类型分为两类:整型(包括字符和布尔类型在内)和浮点型

类型 含义 最小尺寸
bool 布尔类型 未定义
char 字符 8位
wchar_t 宽字符 16位
char16_t Unicode字符 16位
char32_t Unicode字符 32位
short 短整型 16位
int 整型 16位
long 长整型 32位
long long 长整型 64位
float 单精度浮点数 6位有效数字
double 双精度浮点数 10位有效数字
long double 扩展双精度浮点数 10位有效数字

3. 数据类型选择的经验准则

4. 有符号类型和无符号类型

5.初始化与赋值

初始化和赋值是两个完全不同的操作。

6. 声明与定义

7. C++关键字

8. const

8.1 初始化

默认状态下,const对象仅在文件内有效。

在编译的过程中,编译器会把所有用到该const变量的地方都替换成相应的值。所以编译器必须知道变量的初始值,如果存在多个文件的情况下,每个文件必须知道const的初始值(const对象也必须初始化)。但由于默认状态下,const对象仅在文件内有效,当多个文件同时出现同名的const变量时,其实就相当于分别定义了不同的变量。

如果想只定义一次怎么做呢?

只需要无论是声明还是定义都标记extern关键字即可。

//file1.cpp
extern const i=1;
//file2.cpp
extern const i;

如果想要在多个文件之间共享const 对象,必须在变量之前添加extern关键字

8.2 const引用

定义:把引用绑定到const对象上,即为对常量的引用(reference to const)。
引用类型必须与其所引用对象类型一致(但是有两个例外),

8.2.1 与普通引用不同的是不能让非常量引用指向一个常量变量。

    int i= 0;
    const int &ci = i; 
    int &ri = ci;

在这里插入图片描述

因为非常量引用可以修改它所绑定的对象,但是常量引用不能,如果非常量引用指向一个常量变量合理的话,那么非常量引用可以修改它所绑定的对象的值,这显然是不正确的。

8.2.2 初始化常量引用时允许将以任意表达式作为初始值,只要表达式的结果能转换成对应类型即可。

8.2.2.1允许常量引用绑定分常量的对象、字面值,甚至一个一般表达式

    double dval = 3.14;
    const int &ri = dval;
    std::cout<<"dval:"<<dval<<std::endl;
    std::cout<<"ri:"<<ri<<std::endl;

编译器会将上面代码变成:

    const int temp= dval;
    const int &ri = temp;
    std::cout<<"dval:"<<dval<<std::endl;
    std::cout<<"ri:"<<ri<<std::endl;

在这种情况下面,ri绑定了一个临时量

ri不是常量引用的时候会发生错误:

    double dval = 3.14;
    int &ri = dval; // error: invalid initialization of non-const reference of type ‘int&' from an rvalue of type ‘int'
    std::cout<<"dval:"<<dval<<std::endl;
    std::cout<<"ri:"<<ri<<std::endl;

编译器会将上面代码变成:

    int temp= dval;
    int &ri = temp;
    std::cout<<"dval:"<<dval<<std::endl;
    std::cout<<"ri:"<<ri<<std::endl;

由于临时值的特殊性,程序员并不能操作临时值,而且临时值随时可能被释放掉,所以,一般说来,修改一个临时值是毫无意义的,据此,c++编译器加入了临时值不能作为非const引用的这个语义限制。

8.2.2.2 const引用可能用一个非const对象

    int i =0;
    int &ri = i;
    const int &ci = i;
    ci = 2; // error: assignment of read-only reference ‘ci'

常量引用仅对引用可参与的操作做出限定,对于引用的对象本身是不是一个长量未作限定

8.3 const与指针

指针的类型必须与其所指对象的类型一致(但是有两个例外)

允许一个指向常量的指针指向一个非常量对象.

和const引用差不多,指针常量的指针也没有规定所指的对象必须是一个常量

8.3.1 指向常量的指针和常量指针

指向常量的指针(指针可以改变,指针的值不可变):

const int x=1;
const int *p = &x;//p为指向常量x的指针
int *p = &x; //错误,因为p只是个普通指针

常量指针(不变的指针而不是指针指向的值):

int x=0;
int *const p = &x;//p为常量指针(允许一个指向常量的指针指向一个非常量对象.)
const int xx=0;
const int *const pp= &xx;//pp为指向常量的常量指针(
    int x=0;
    int y = 11;
    const int *p = &x;//p为常量指针(允许一个指向常量的指针指向一个非常量对象.)
    int  *const cp = &x;
    const int *const pp= &x;//pp为指向常量的常量指针

    x = 1;
    std::cout<<"x:"<<x<<std::endl;
    std::cout<<"*p:"<<*p<<std::endl;
    std::cout<<"*cp:"<<*cp<<std::endl;
    std::cout<<"*PP:"<<*pp<<std::endl;
    p = &y;
    *p = 11; // error: assignment of read-only location ‘* p'
    *cp = 12;
     cp = &y;// error: assignment of read-only variable ‘cp'
    std::cout<<"*p:"<<*p<<std::endl;
    std::cout<<"*cp:"<<*cp<<std::endl;

小结:

常量指针,指针本身是一个常量,不可以改变指向的对象,但是可以改变指向对象的值,可以使用解引符改变地址所指向的值
指向常量的指针,可以重新指定指向新的对象,但是不可以改变对象的值.

    int errNumb =0;
    int *const curErr = &errNumb; // curerr 将一直指向errNumb errNumb 的值变化了curerr的值也跟着变化
    const double pi = 3.14159;
    const double *const pip = &pi; // pip 是一个指向常量对象的常量指针
    std::cout<<"curErr:"<<*curErr<<std::endl;
    std::cout<<"pip:"<<*pip<<std::endl;
    errNumb =1;
    std::cout<<"curErr:"<<*curErr<<std::endl;

输出:

curErr:0

pip:3.14159

8.3.2 顶层const和底层const

指针如果添加const修饰符时有两种情况:

顶层const:表示指针本身是一个常量
底层const:表示指针所指向的对象是一个常量

9. constexpr 和常量表达式

常量表达式(const experssion):是指
1.值不会改变 并且
2.在编译过程就能得到计算结果的表达式。

字面量属于常量表达式,用常量表达式初始化的const对象也是常量表达式。

9. 1 constexpr 变量:

一般来说,如果 你认定变量是一个常量表达式,那就把它声明成constexpr类型函数:

constexpr函数是指能用于常量表达式的函数。

应遵循的约定:函数返回类型及所有形参的类型都是字面值类型,而且函数体中必须有且只有一条return 语句。

constexpr函数体内可以有其他语句,只要这些语句在运行时不执行任何操作。(例如,空语句、类型别名和using声明等)

constexpr函数被隐式地指定为内联函数。

9. 2字面值类型

常量表达式的值需要在编译时就得到计算,因此对声明constexpr时用到的类型必须有所限制。因为这些类型一般比较简单,值也显而易见、容易得到,就把它们称为“字面值类型”(literal type)。

字面值类型范围:

算术类型、引用和指针都属于字面值类型。某些类也是字面值类型,它们可能含有constexpr函数成员。自定义类Sales_item、IO库、string类型不属于字面值类型。

9. 3constexpr 和指针

尽管指针和引用可以定义成constexpr,但它们的初始值受到严格限制。一个constexpr指针的初始值必须是nullptr、0或存储于某个固定地址中的对象。

constexpr int *q = nullprt 等价于 int const *q = nullprt

函数体内定义的变量一般来说并非存放在固定地址中,因此constexpr指针不能指向这样的变量。定义于函数体外的对象其地址固定不变,能用来初始化constexpr指针。

允许函数定义一类有效范围超出函数本身的变量,如局部静态变量,这类变量和定义在函数体之外的变量一样有固定地址,因此constexpr引用能绑定到这样的变量上,constexpr指针也能指向这样的变量。

10. 处理类型

10.1 类型别名 typeof

typedef double a;
typedef wages base,*p; //等价于 double base ,*p;

using

using SI = Sales_item;
SI item;//等价于 Sales_item item;

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

您可能感兴趣的文章:
阅读全文