c++/c 学习笔记-基础(1)


1.基本内置类型

1.1 wchar_t ,char16_t,char32_t为扩展字符集,和bool类型一样,均无signed/unsigned 修饰类型。

1.2 char的实现可能为unsigned或signed,具体由编译器决定,bool的实现并未明确,所以二者均不能用于存储数据。

1.3 char-8,short-int-16,long-32,long long-64最小的实现位宽(具体以系统而定),float-6,double-10,最小的实现有效数字位数,wchar_t -8,char16_t-16,char32_t-32固定大小。

1.4 若把将一个超出无符号类型范围的值赋给一个该无符号类型,结果为该值对无符号类型表示的总值取模。(这个话听着拗口,说白了便是把这个值在底层以无符号值予以对待),相反若将一个超出有符号类型范围的值赋给一个有符号类型,结果则未定义。从这里可以看出,在C++中若有符号和无符号混和参加运算时,有符号数必须会转为无符号数参加运算。这个可能造成很多误会。

1.5 字面值常量

1.5.1整形(int)字面值常量 30 /*十进制*/ 030/*八进制*/ 0x30/*十六进制*/

1.5.2浮点型(double)字面值常量,其可表示为一个小数或以e/E科学计数法表示的指数。如: 3.14   3.14E0,      0.,    0e0,    .001

1.5.3 字符型(char/char*)字面值常量,其用单引号表示一个字符,双引号表示字符串,编译器会在字符串后自动添加结束符。另还存在一些转义字符.如:\n;\r;\\;\";\';\t;\?等。

1.5.3可以直接指定字面值的类型。字符在前,数在后。 u -char16_t(UTF-16字符);   U-char32_t(UTF-32字符),  L-wchar_t, u8-char(注,仅用于字符串常量,UTF-8)

1.5.4 bool 类型的字面值为true或false,指针字面值为nullptr,当然对于一个nullptr的指针调用*,则会运行时报错;

2.变量

2.1 变量初始化

2.2对于内置类型,若定义于任何函数之外的变量被初始化为0,而在函数体之内则不会被初始化。

2.3C++11开始支持共四种初始化方式,    int a = 0; int a = {0}; int a{0}; int a(0);其中{}的两种称为列表初始化方法,此方法有一个重要特点,当其中有信息丢失时,编译器会报错,这意味着从大类型转为小类型时的若{}则不能编译通过,小类型转为大类型则不会。例如 float f = {1.0}便会报错,原因由于1.0字面值是一个double,使用{}转为float便会丢失信息。

2.4 在嵌套作用域中的同名变量会覆盖外部作用域同名变量。

3.复合类型和const 限定符

C++中的三种类型修饰符 左引用 右引用 指针

3.0 右值 左值

所谓右值 便是即将消失的值或字面值, 如a +b,33等,对一个右值求内存地址是会报错的,左值便是可求地址的。

3.1左引用&

引用并非对象,只是对所引用的对象的一个别名,一旦绑定,便不可更改。所以由此我们可以推出,对于非const引用,必须初始化;必须类型相同;必须是一个对象(左值)。而对于const引用,意即不可通过此引用来修改原值,此此可以推出,其类型相同,直需基本类型相同即可,其值亦可为一个右值。

3.2 指针*

3..2.1指针本身便是一个对象,其指针必须在定义时赋初值。与引用不同,指针在其生命过程中可以指向多个对象。指针不能指向一个临时的右值。

3.2.2指针的值(地址)应属于下列4种状态之一,指向一个对象;指向紧邻对象所占空间的下一个位置;空指针;无效指针。

3.2.3 void* 可以用于存放任意类型对象地址,可以用于和指针比较,作为函数输入和输出,或者赋给另一个void*指针。但不能直接操作其所指对象。

3.2.4 指针是一个对象,所以const 在指针中有两个位置可出现。一是表明指针本身为const,另一是指针所指对象为const.此前一个意思指指针地址不可更改,后一个指所指对象不可再更改。const 所在位置* 前指指向对象,在后指地址本身。 const int * const ptr =nullptr;此处还有一个概念顶层const指的是指针地址的const,而底层const 表示指针所指对象const.

3.3右引用&&

3.4 复合类型的声明。对于各个修饰符复合的情况,应该注意,指针*,引用&,&& 并不是类型,所以对于 int* p,b 此种类型说明,b并不是一个int* ,仅是一个Int型。对于指针和引用的复用,由于引用并不是一个对象,所以指针是不能指向一个引用的,而指针是一个对象,所以可以建立一个引用指针。如int b =0;  int *&a=&b;(此处a是一个引用,引用一个指针指向int,此指针用b初始化),或int* b =nullptr; int*&a=b;(同上)

4.constexpr 和常量表达式

常量表达式是指在编译时便具有明确的值的。如const类型从一个字面值赋值便是一个常量表达式,但对于一个返回const 限制符类型的函数便便不是一个常量表达式。

constexpr,则不存在这样的问题,constexpr函数同样是常量表达式。此处。对于于指针constexpr是一个顶层const限制,如constexpr int* a是指针a不可修改,而并非其所指对象。

5.处理类型

5.1 auto是以 类型推断.

5.1.1编译器通过初始值推断类型,所以auto 声明的变量必须初始化,也就是说auto 不能从一个字面类型推断,但可以在auto上添加const,如const auto a = 32;

5.1.2auto不能扩展推断,继承cv限定符。如unsigned a =4294967295; unsigned b =1;auto c=a+b,此时a+b会溢出,但auto并不能自动升级类型,依然会以unsigned来处理。

#include <iostream>
#include <limits>
using namespace std;

int main() {
	cout << numeric_limits<unsigned int>::max()<<endl;
	unsigned int  b = numeric_limits<unsigned int>::max();
	auto a = b + 1;
	cout << a;// 输出 0
	return 0;
}

对于原类型中的cv限定符,auto的继承中全部不予处理 ,如:const int a =3;auto b =a;此时a的类型是int,而非const.,但需要注意对于 类似 auto b = &a,此时b是一个int * const类型

#include <iostream>
#include <type_traits>
#include <typeinfo>
using namespace std;

int main() {
	const int b = 0;
	auto a = b;
	auto ca =&b;
	cout << is_const<decltype(a)>::value<<endl; //输出 0
	cout << typeid(ca).name();// 输出 int const*,此时的const是顶层的,即意味着对地址的,而并非所指对象的const
	return 0;
}

5.1.3auto可以和指针与引用合用。切记一点的是指针是一种类型,而引用不是,所以auto可以推断出指针,不能推断出引用。所以若在auto上添加修饰符时,我们可以理解将auto转为相应的类型即可,另,若auto推断出是一个指针,再添加修饰符,此时并不‘*’并不迭加,而仅是合并,这便冗余忽略。如 int* a =nullptr; auto* b =a; 此时b是一个int*类型。

#include <iostream>
#include <type_traits>
#include <typeinfo>
using namespace std;

int main() {
     int* b = 0;
    auto val1 = b;
    cout << is_pointer<decltype(val1)>::value<<endl; // 输出 1,表明是一个指针
    cout <<typeid(val1).name()<<endl;//输出 pi
    auto* val2 = b;
    cout << is_pointer<decltype(val2)>::value<<endl;// 输出1,表明是一个指针
    cout<<typeid(val2).name()<<endl;//输出 pi



//上面表明在多个指针冗余时,会忽略。
    int v =0;
    int& rv =v;

    auto val3 =rv;
    cout <<is_lvalue_reference<decltype(val3)>::value<<endl;//输出 0,表明不是左值引用,即引用并不继承
    auto& val4 =rv;
    cout <<is_lvalue_reference<decltype(val4)>::value<<endl;//输出1,表明是一个左值引用。

    //auto* val5 = rv; //无法通过编译,指针不能指向 一个引用,参见上3.4
    //cout<< is_lvalue_reference<decltype(val5)>::value<<endl;
    //cout << is_pointer<decltype(val5)>::value<<endl;

    auto& val6 = b;
    cout<< is_lvalue_reference<decltype(val6)>::value<<endl; //输出1,表明是一个左值引用
    cout << is_pointer<decltype(val6)>::value<<endl;//输出0,表明不是一个指针
    cout << typeid(val6).name();//输出Pi,表明其是一个引用,且引用的对象是一个指针
    return 0;
}



5.1.4 auto不能用于数组生成,若为数组,便会自动转为一个指针。如:

#include <iostream>
#include <typeinfo>
using namespace std;

int main() {
	int b[5]={0};
	auto a =b;
	cout << typeid(a).name(); //输出  pi
	return 0;
}

5.2 typedef 中关于const 的问题。当typedef 一个复合类型时如 typedef char* pstring; const pstring cstr =0; 此处cstr前的const是指顶层const,即cstr不可更改。const pstring* ps此种亦是雷同的,即ps 指向此种顶层const char*指针。

5.3 decltype 类型推断。

5.3.1 decltype 可以通过表达式推断出类型。即并不是以后类型来推断的,所以对于引用(左值,右值)、const,数组,可以进行继承和推断的,但与auto对于冗余符合处理是一样,对冗余cv 修饰符会忽略的。void是不可推导的。

其推断规则为:
5.3.2 如果e 是一个没有带圆括号的标记符表达式或者类成员访问表达式,那么decltype(e) 就是e所命名的实体类型,此外,如果 e 是一个被重载的函数(这里指的函数类型,而非函数返回值),则会导致编译时错误。

5.3.4 否则,假设e的类型是T,如果e是一个将亡值,那么decltype(e)的类型为T&&

5.3.5 否则,假设e 的类型是T,如果e是一个左值,则decltype(e)为T&,此处应注意,若不为原本的变量,凡是带有操作符的,如(),++,[],*包括字符串等,其结果后仍可赋埴的,均为左值。

5.3.6否则,假设e的类型为T,则decltype(e)为T;此时仅指为其基本类型。

#include <iostream>
#include <type_traits>
#include <typeinfo>
using namespace std;

int main() {
	int i =0;
	int arr[5] ={0};
	int *ptr =arr;
	struct S { double d;} s;
	int& ri = i;

	void overloaded(int);
	void overloaded(char);

	int && rvalref();
	const bool func(int);

	decltype(arr) var1;
	cout<<typeid(var1).name()<<endl; //int arr[5]
	decltype(ptr) var2;
	cout<<typeid(var2).name()<<endl;//int*
	decltype(s.d) var3;
	cout<<typeid(var3).name()<<endl;//double
	decltype(ri) var4 =i;//左值引用
	cout<<typeid(var4).name()<<endl;//int
	cout<<is_lvalue_reference<decltype(ri)>::value<<endl;//1

	//decltype(overloaded) var4;

	//第二种情况,直接为一个右值引用。
	decltype(rvalref()) var5=1;
	cout << is_rvalue_reference<decltype(rvalref())>::value<<endl;//1

	//此为第三种情况,结果为表达式,且为左值。
	decltype(true?i :i) var7=i;
	cout << is_lvalue_reference<decltype(true?i:i)>::value<<endl;//1
	decltype((i)) var8=i;
	cout<<is_lvalue_reference<decltype((i))>::value<<endl;//1
	decltype(++i) var9=i;
	cout<<is_lvalue_reference<decltype(++i)>::value<<endl;//1
	decltype(arr[3]) var10=i;
	cout<<is_lvalue_reference<decltype(arr[3])>::value<<endl;//1
	decltype(*ptr) var11=i;
	cout<<is_lvalue_reference<decltype(*ptr)>::value<<endl;//1
	decltype("lvar") var12="lvar";
	cout<<is_lvalue_reference<decltype("lvar")>::value<<endl;//1
	cout<<typeid(decltype("lvar")).name()<<endl;//字符串的类型是一个const char array[5]的引用,其中数组大小和字符串大小长度有关

	//第四种情况,仅返回类型,无修饰符。
	decltype(1L) var13; //本类型,除字符串字面常量为右值,
	cout<<typeid(decltype(1L)).name()<<endl;//long
	decltype(i++) var14; //返回类型,虽i++返回右值,为第四种情况,返回Int
	cout<<is_rvalue_reference<decltype(i++)>::value<<endl;//0
	decltype(func(1)) var15 ;//返回类型bool,虽结果为const bool,此处若用vs2013编译时,会产生bug,
                                 //其产生const bool类型,不可更改变量值,但若用is_const<>去检测,结果却是1.
	cout<<typeid(decltype((func(1)))).name()<<endl;//bool
	cout<<is_const<decltype((func(1)))>::value<<endl;//0
	return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值