普通类型

数字类型

说是数字类型,其实不止int, float那些,在c++中,boo, char, wchar_t, char16_t, char32_t等等都是。

  • char 八个位
  • int 十六个位
  • wchar_t 十六个位
  • long 三十二个位

使用sizeof在x64机器上打印出(单位是byte):

  • short 2
  • int 4
  • long 4
  • char 1

似乎在x64上int和long是一样大的。
由于历史原因,在微软的机器上,由于历史愿意这样。

单精度与双精度
单精度占用4个字节,双精度占用8个字节。
单精度有:一个符号位,八个exp位,23个数字位;
双精度有:一个符号位,11个exp位,52个数字位。

unsigned和signed关键字

决定有没有符号位。

  • 当你知道你的变量不可能为负值的时候,可以使用unsigned。
  • 不要单纯地使用char类型来代替short。因为在不同的机器上,有些char是unsigned的,有些是signed的。如果你非要这么用,就加上unsigned或者signed。
  • 能用double就用double。float经常会不够用。而且在某些机器上double还比float要快。

自动转换

bool b = 43;
int i = b; // 1
i = 3.14; // 3
double pi = i; // 3.0
unsigned char c = -1; // 255
signed char c2 = 255; // 确实不是255,但转成unsigned short之后打印出来还是255。给一个signed short赋值一个超过127的值会导致不可知后果,俗称undefined。
cout << true; //出来是1,cout对于bool变量只会输出1或者0
unsigned u = 10;
int i = -48;
cout << u + i; //32-bit的int会出来一个超大的数

两个unsigned做运算,如果出现了负数,会被变成signed int。
由于unsigned永远不可能小于0,所以拿来while(u >= 0)做比较的话,会必然是true然后一直运行。

unsigned和signed不要做混合运算,会出事儿。

写法

010 八进制
0x10 十六进制

string写法

L`a` // wchar_t
u8"hi" //char (utf8)

list初始化

int a = {0};
long double b = 3.1111;
int c = {b}; //报错,会丢失信息
int d = b; //通过

外部变量

extern int i; // 声明了但是没有定义
int j; // 声明且定义

extern double pi = 3.14; //声明且定义

一个变量只能被定义一次,但是可以被声明多次。变量只能在某个一个文件里定义一次,但是可以在各个地方被声明。
在方法里对extern进行初始化会导致报错。错误会比如是error: pi has both extern and initializer

keywords

像是andornot这种关键字,主要是以前qwer键盘还不流行的时候用的,因为那个时候的键盘可能没有||或者&&之类的字符。
其实我觉得这样挺lua,挺好的。

作用域

  • global scope
  • block scope
  • nested scope
    同样的变量名,外部的变量会内部的变量屏蔽。
#include
int p = 10;
int main(){
    int p = 20; // 一般不建议这么做
    cout << p; // 这里的p其实是另一个东西了,外面的p被屏蔽 --> 20
    cout << ::p; // --> 10;
}

复合类型

引用

int ival = 1024;
int &refval = ival; // 相当于起了个别名而已
int &refval2; // 一定要初始化,错
int &i1 = ival, i2 = ival; // i1是个引用,i2则不是
int &refVal4 = 10; // 右值一定要是一个object
double dval = 3.14;
int &refVal5 = dval; // 不行的,做不到的

一定要初始化,不存在rebind的。
理解为别名就最容易了,其它的不要多想。

指针

获得指针

int i = 10;
int *p = &i;

获得指针所指对象

*p = 100;
cout << *p;

传一个指针过去,使得可以在另一个函数内改变基础变量(aka,非instance):

#include
using namespace std;
void changeValue(int* p){
    *p = *p + 50;
}

int main(){
    int i = 10;
    changeValue(&i);
    cout << i << endl;
    cout << *&i << endl;
}

不同类型的指针不允许相互赋值

double d = 3.14;
double *p1 = &d;
int *p2 = p1; // error
int *p2 = &d; // error
int &ref = *p; // 对p所指的int进行引用

空指针

int *p = nullptr; // 自动赋值为0
int *p2 = 0; // 直接赋值为0

int i = 0;
int *pp2 = i; // 这样又不行

// 必须 #include
int *p3 = NULL;

// 是否为空指针
if(p){
    
}

注意
很容易眼花看错以为是创建了一个值为0的int并把它的值赋给了p。对于一个指针来说,0就代表着空指针!所以没有所谓的真正的空,0即是空。

使用gcc编译的时候,会出现一个nullptr was not declared in this scope的问题,查出来说编译的时候需要加上-std=c++11的参数,其它的c++11特性应该也是需要这个的。

NULL需要一个cstdlib库。在编译之前,编译器会先执行preprocessor,初始化了NULL的值。NULL不属于任何命名空间,所以也不需要使用std:NULL的形式来访问。


最好每个指针都要初始化,起码要给个空指针。不然的话你都不知道它会指到哪里。
不像脚本语言没初始化的时候就默认为nil,c++这边的空指针,是要手写的。。。

引用与指针的区别

  • 引用只可以初始化一次,而后它的值就不允许更改。可以视为是一个别名。

void*

可以指向任何object,可以等同于任何其他类型的指针。由于没有类型,所以不能实例化(?)。可以和任何类型的指针作比较。
一般单纯地用来处理内存。

一种恶心的写法

int i = 1024, *p = &i, &ref = i;

指向引用的指针

有毒。
诀窍是从右往左读。

int i = 10;
int *p;
int *&r = p;
r = &i;
*r = 100; // now the value of i is 100

Const

  • 不可被改变的值。
  • 一定要初始化,不然编译不过。
  • 所谓的const,在编译期间就会被替换为对应的值。

你可能感兴趣的:(普通类型)