二、变量和基本类型

本文适合对于c++有一些基础的人阅读,指出一些容易被忽略的点。
本文包括长整型和整型转化,无符号和有符号转化,字面常量的默认类型;普通初始化方式和列表初始化方式;声明和定义的区别;命名规则;指针和引用的区别;const的用法;类型推断等。

2.1 基本内置类型

算数类型

bool;char;wchar_t;int;long;long long;float;double…

注意:当等式同时存在小字节和大字节数时,小字节->大字节。

案例:

    int32_t a = INT32_MAX;
    cout.setf(ios::showbase);
    cout << dec << "a = " << a << hex << "(" << a << ")" << endl;
    cout << dec << "(int64_t)a = " << (int64_t)a << hex << "(" << (int64_t)a << ")" << endl;
    a = INT32_MIN;
    cout << dec << "a = " << a << hex << "(" << a << ")" << endl;
    cout << dec << "(int64_t)a = " << (int64_t)a << hex << "(" << (int64_t)a << ")" << endl;
    uint64_t b = INT64_MAX;
    cout << dec << "b = " << b << hex << "(" << b << ")" << endl;
    cout << dec << "(int32_t)b = " << (int32_t)b << hex << "(" << (int32_t)b << ")" << endl;
    b = INT64_MIN;
    cout << dec << "b = " << b << hex << "(" << b << ")" << endl;
    cout << dec << "(int32_t)b = " << (int32_t)b << hex << "(" << (int32_t)b << ")" << endl;
    a = -2, b = 1;
    auto c = a + b;
    cout << dec << "c = " << c << hex << "(" << c << ")" << endl;			

输出:

a = 2147483647(0x7fffffff)
(int64_t)a = 2147483647(0x7fffffff)
a = -2147483648(0x80000000)
(int64_t)a = -2147483648(0xffffffff80000000)
b = 9223372036854775807(0x7fffffffffffffff)
(int32_t)b = -1(0xffffffff)
b = 9223372036854775808(0x8000000000000000)
(int32_t)b = 0(0)
c = 18446744073709551615(0xffffffffffffffff)

解释:小字节变成大字节正数填8个0x0,负数填8个0xf,大字节变小字节会出现问题,正数去掉8个0xf,负数去掉8个0x0。应避免小转大。

有符号和无符号

int;unsigned int…

注意:当等式同时存在有符号和无符号时,有符号->无符号。

案例:

    int a = -2;
    unsigned b = 1;
    auto c = a + b;
    cout.setf(ios::showbase);	//设置输出十六进制前的0x
    cout << dec << "a = " << a << "(" << hex << a << ")" << endl;
    cout << dec << "(unsigned)a = " << (unsigned)a << "(" << hex << (unsigned)a << ")" << endl;
    cout << dec << "b = " << b << "(" << hex << b << ")" << endl;
    cout << dec << "(int)b = " << (int)b << "(" << hex << (int)b << ")" << endl;
    cout << dec << "c = " << c << "(" << hex << c << ")" << endl;
    cout << dec << "(int)c = " << (int)c << "(" << hex << (int)c << ")" << endl;
    cout << dec << "(unsigned)c = " << (unsigned)c << "(" << hex << (unsigned)c << ")" << endl;

输出:

a = -2(0xfffffffe)
(unsigned)a = 4294967294(0xfffffffe)
b = 1(0x1)
(int)b = 1(0x1)
c = 4294967295(0xffffffff)
(int)c = -1(0xffffffff)
(unsigned)c = 4294967295(0xffffffff)

解释:有符号无符号之间转化bit位并未变化。有符号无符号类型相加的结果对于bit位来说是相同的,只是默认解析为无符号型。

字面常量

整数:24十进制(是有符号的),024八进制(有符号和无符号都有可能),0x24十六进制(有符号和无符号都有可能),他们都自动转化成可容纳他们最小的那种类型。

浮点数:3.14默认是double类型。

字符&字符串:单引号’a’为字符,双引号“abc”为字符串(字符数组)默认以’\0结尾’。

指定字面值的类型:

​ 前缀(字符):u/U/L/u8

​ 后缀(数字):整u/l/ll; 浮f/l(可大写)

布尔类型:false/true

指针:nullptr

2.2 变量

变量初始化

列表初始化:int a = 0; int a = {0}; int a(0); int a{0};

注意:{}方式c++11后才可以友好的使用。{}方式需要显示转化数据类型,()可能存在隐式转化。

案例:

    double a = 3.14;
    int b = a;
    int c(a);
    int d = {a};	//warning
    int e{a};		//warning

输出:

warning: narrowing conversion of 'a' from 'double' to 'int' inside { } [-Wnarrowing]

解释:{}会检查类型。
注意:{}还会先调用列表初始化,而后在考虑构造函数,而()只能调用构造函数

案例:

    vector<int> v1(10);
    vector<int> v2{10};
    cout << v1.size() << endl;
    cout << v2.size() << endl;

输出:

10
1

解释:()调用的是vector的构造函数,而{}优先调用列表初始化,相当于v2.append(int(10))。

默认初始化:int a;

注意:内置数据类型默认初始化会出现随机值,难以调试。

变量的声明和定义

声明:只是指定类型和名字 extern int a;

定义:申请空间,可能初始化 int a = 10;

标识符

变量的名字:必须是数字字母下划线组合,且数字不能开头。

命名规则:大驼峰SetValue,大驼峰setValue,匈牙利set_value

命名规范:宏定义全大写,类定义大驼峰,变量名匈牙利,函数小驼峰或者匈牙利。

名字的作用域

全局作用域和局部(块)作用域 ::
每个花括号都代表独自的作用域,即使他们是匿名的。

2.3 复合类型

指针

不管理内存的指针,int a = 0; int* b = &a; b指向a的内存空间,可以通过b间接访问a;

管理内存的指针,int* b = new int(0); …… delete b; b直接管理这一块内存区域。

注意:可以把指针当作uint32_t或者uint64_t类型,32位操作系统指针大小位32bit,64位操作系统指针大小位64bit。

​ 应该避免出现:野指针(使用指向无效或已被释放内存的地址)、内存泄漏(管理内存的指针未释放内存就改变指向)、双重释放(管理内存的指针释放了两次)。

​ 不管理内存的指针:要保证使用时,内存空间是有效的。(野指针)weak_ptr/shared_ptr。

​ 管理内存的指针:在不再使用内存空间时,释放且只释放一次内存。(内存泄漏、双重释放)shared_ptr。

引用(左值引用)

int a = 0; int& b = a;可以理解为为变量取别名。

注意:a的生命周期一定大于等于b。

​ 也可以将其理解为指针常量(int * const b = a),指针的指向不能变。

2.4 const限定符

初始化

const初始化:修饰变量为只读。

注意:const只有在本文件内有效,需要在头文件中定义extern;

常量引用:以只读的方式引用变量,变量可以不是const。int a = 0; const int& b = a;

注意:常量引用,当引用和被引用类型不一致时。

案例:

    double a = 3.14;
    const int& b = a;
    a += 1;
    cout << "a = " << a << ", b = " << b << endl;

输出:

a = 4.14, b = 3

解释:上面代码等价于double a = 3.14;const int temp = a; const int &b = temp;

​ b 绑定到了临时变量上,这并不是我们想要的结果。const &可以绑定到临时变量,而&是不可以的。

​ &&也可以绑定到临时变量,它等价于const & + const_cast的组合。

pointer to const(const *):意思是此指针为只读指针,不可以对指向的内存空间进行修改。

const pointer(* const):意思是此指针的指向不能改变。

const成员函数

const成员函数不可以修改(除mutable修饰,或static修饰的变量)。

const的对象只能调用const方法,非const对象优先调用非const方法,也可以调用const方法。

constexpr表达式

在编译时就可以计算出的结果。

constexpr修饰的函数,其入参一定也都是constexpr。

constexpr修饰构造函数,构造函数一定为空,只能在初始化列表中初始化成员变量。

2.5 处理类型

类型别名

便于更好的理解程序。typedef unsigned long long uint64_t; using unsigned = size_t;

注意:typedef char *pstring; const pstring cstr = nullptr; cstr其实是char * const,而不是const char *。

类型推断

auto:编译器自动推断类型。

注意:auto会忽略引用、* const和普通变量的const,只会保留const *。

decltype:类型推断但不使用其值。

注意:与auto不同在于它会保留const,和引用。

​ int *p; decltype(*p) => int&。*p的类型也是引用。

​ int i; decltype((i)) => int&。(expression)的返回值都是引用。

2.6 自定义数据结构

struct name {};

与class不同在于所有变量和函数默认为public。

头文件定义时需要有头文件保护#ifndef __NAME_H__ #define __NAME_H__ …… #endif。

发布了10 篇原创文章 · 获赞 11 · 访问量 2757

猜你喜欢

转载自blog.csdn.net/waxtear/article/details/104112295