C++_1——基本数据类型

  这一系列文章的目的是在学习了C++基础后,继续补充一些C++基础和进阶的知识点,包括C++11的相关内容。

A 简单数据类型

a1 整型

  c++提供的基本整型包括char、short、int、long、long long(c++11)及其无符号版本,共十种。

 整型长度问题

  c++中,整型的长度不是固定的,取决于系统,基本情况如下面的表所示,可以使用sizeof()来确定具体系统中整型的长度。 整型变量 长度
short 至少16位
int 至少与short一样长
long 至少32位,且至少与int一样长
long long 至少64位,且至少与long一样长

  实际上,一个字节(bytes)未必是8位(bit),具体的取值取决于字符集的数目,比如ASCII这个字符集,8位即可表示所有字符集中的字符,因此是8位,而在Unicode中,可能会用到更大的字符集,8位就不够了。一般,在8位字节系统中,short为2字节,int和long为4字节,long long 为8字节。

 cout输出不同的进制

    std::cout<<std::hex;    //后续的数值以16进制显示
    std::cout<<std::oct;    //后续的数值以8进制显示

 整型常量

整型常量类型一般是int,除非有特定后缀或值过大。
  ① 后缀包括(u无符号,L长整型,LL及其组合),如23333L,23456uL。
  ② 值过大,对于十进制整型,会选择能装下该值的有符号最小类型,对于8/16进制整型,会选择能装下该值的无符号最小类型。

 char & wchar_t

1 字符型char:
  ① 8位,满足常见的ASCII或者EBCDIC字符集(Unicode的一个小子集),可用单引号行形式表示字符,可直接表示(‘A’)、或通过反斜杠进制数(‘\012’、‘\0xa’)。
  ② char既可能有符号,也可能无符号,取决于c++实现,但可以显式地指定。存储ASCII可用默认,因为ASCII只需要低七位,128个字符。

2 宽字符型wchar_t:
  ① 需求无法满足,位数需要多于8位,表示扩展字符集。
  ② 与之对应的是wcin和wcout,用于处理wchar_t流。
  ③ 显式表示宽字符常量或字符串常量,加前缀L,如表示宽字符P:L‘P’。

 ASCII、Unicode、ISO10646

  ① ASCII是Unicode子集。
  ② Unicode 为各种字符和符号提供标准数值编码,每个字符的编号称为码点
以\u开头 以\U开头
用8个十六进制位表示的通用编码名 用16个十六进制位表示的通用编码名

  ③ ISO10646和Unicode相似,都是通用字符编码,两者标准同步。

 C++11 新整型

1、char16_t / char32_t char16_t char32_t
无符号,长16位 无符号,长32位
前缀u 前缀U

2、size_t
  1)size_t在不同架构下的定义不同。
  2)32位系统下一般定义为unsigned int ,占4字节;64位系统下一般定义为unsigned long,占8字节。
  3)size_t方便移植程序,如计数等操作,保证能容纳实现所建立的最大对象的字节大小。

3、long long 和 unsigned long long

a2 浮点型

  ① 浮点型包括float、double、long double。
  ② 浮点型常量一般是double。
  ③ 指数范围一般是-37~37。
  ④ 浮点型的位数表示的是有效位数,float一般32位,double一般64位。

a3 类型转换

 整型提升

    1 如果有一个操作数的类型是 long double,则将另一个操作数转换为 long double。
    2 否则,如果有一个操作数的类型是 double,则将另一个操作数转换为 double。
    3 否则,如果有一个操作数的类型是 float,则将另一个操作数转换为 float。
    4 否则,说明操作数都是整型,因此执行整型提升。
    5 在这种情况下,如果两个操作数都是有符号或无符号的,且其中一个操作数的级别比另一个低,则转换为级别高的类型。
    6 如果一个操作数为有符号的,另一个操作数为无符号的,且无符号操作数的级别比有符号操作数高,则将有符号操作数转换为无符号操作数所属的类型。
    7 否则,如果有符号类型可表示无符号类型的所有可能取值,则将无符号操作数转换为有符号操作数所属的类型。
    8 否则,将两个操作数都转换为有符号类型的无符号版本。

 强制转换

//1 通用 
    (typename) value    
    typename (value)        
 //2 C++11
    static_cast<typename> (value)

a4 类型别名

C++允许给类型建立别名,建立方式有两种:

    #define aliasName typeName
    #define BYTE char

    typedef typeName aliasName;
    typedef char byte;

但前者只是简单替换,有时不适用,举例如下

    #define FLOAT_POINTER float*

    FLOAT_POINTER a,b;  //等价于 float* a,b; 这样b只是一个float

B 复合数据类型

b1 数组

1 数组全部初始化为零,有以下几种方式
  ① 显式全部初始化为0

    int array[3] = {0,0,0};

  ② 循环遍历每个元素初始化为0
  ③ 利用编译器的特点,显式地初始化第一个元素为0,编译器将其他元素设为0

    int array[3] = {0};

  ④ C++11新特性中,列表初始化可省略等号,当大括号内没有值时,所有元素将被初始化为0

    int array[3] = {};
    int array[3]{}; //作用同上

b2 字符串 C-string

这里讨论C-风格字符串,不讨论string类。

1 结尾空字符 \0
  ① 字符串常量结尾隐式添加 \0
  ② 字符串数组的sizeof()和strlen(),前者计算数组大小,后者只计算不包括空字符的字符串长度

    char str[10] = "abcdefg";
    sizeof(str);//10
    strlen(str);//7

2、原始字符串 raw string
  1)原始字符串将保证字符串内容不加修改地输出,转义字符将以两个常规字符的形式表示。
  2)方法是使用定界符 "()" 并通过前缀R来表示原始字符串,如下:

    std::cout<<R"(aaa "bbb" ccc"\n")"<<std::endl;
    //输出:  aaa "bbb" ccc"\n"

  3)如果字符串内容中包含 )" ,当编译器见到第一个 )" 时,会认为字符串结束,就会造成错误。解决方法是定义一个特殊的定界符,规则是在引号与括号之间增加任意字符,同时保证首尾增加的字符是一样的,如下:

    std::cout<<R"+6(aaa "bbb" ccc"\n")+6"<<std::endl;//这里定义了 "+6( 和 )+6" 的定界符,其中增加了+6这些字符
    //输出:  aaa "bbb" ccc"\n"

  当然,任意字符,不包括空格、左右括号、斜杠、控制字符(制表符、换行符等)。

b3 结构体 struct

1 C++11结构初始化

    struct myStructType
    {
        int id;
    };
    myStructType myStruct{};    //这将结构内成员都设置为0

b4 共用体 union

1 意义:数据项使用两种或更多格式的时候(不同时使用不同格式),常用于节省内存。
2 共用体的长度为其最大成员的长度。

b5 枚举 enum

1 定义,枚举含有多个枚举量,每个枚举量,对应到从0开始的整数,或显式地赋值,当显示赋值部分枚举量时,未赋值的量对应的整数为前一个加1

    enum myEnumType{a,b,c,d,e,f,g};
    enum myEnumType{a = 8,b,c,d,e,f,g};

2 枚举只有赋值运算符,枚举可提升为整型
3 整型可强制转换为枚举量,前提是整型的值在枚举范围内,枚举范围的上限是大于最大值的最小2的幂再减1,对于下限,最小值大于0,则下限是0,否则与上限规则类似
4 应用:定义符号常量用在switch等地方

    enum {a,b,c,d,e,f,g};

    int main()
    {
        int code = 1;
        switch (code)
        {
            case a : break;
            case b : break;
            default : break;
        return 0;
    }

5 C++11:作用域内枚举
  1)对于下面的情况,在同一个作用域内定义相同的枚举量,会出现冲突

    enum egg {Small, Medium, Large};
    enum apple {Small, Medium, Large};

  2)C++11提供了一种新枚举,枚举量的作用域为类或结构体,使用枚举名来限制枚举量

    enum class egg {Small, Medium, Large};
    enum class apple {Small, Medium, Large};
    enum struct peach {Small, Medium, Large};
    enum struct box {Small, Medium, Large};

    egg s = egg::Small;

  3)常规枚举能够实现整型提升,但作用域内的枚举不能隐式转换为整型。
  4)作用域内枚举的底层类为int,可以通过下述方式修改底层类型,底层类型必须为整型。

    enum class : short egg{Small, Medium, Large};

b6 指针

1 动态联编(dynamic binding)与内存泄露(memory leak)
  new/delete配对使用。
  同一个内存重复释放将导致不确定的结果,应避免,例如不能创建两个指向同一个内存块的指针。
  动态数组分配内存后,系统程序跟踪分配的内存量,但是跟踪结果不公开,不能通过sizeof来确定动态数组包含的字节数。

2 指针算数
  1)指针算数:指针变量+1,代表指向下一个元素的地址:例如指向double类型的指针,值+1,则指针指向的地址+8。
  2)数组名与指针
  一般情况下,C++将数组名解释为数组第一个元素的地址,stack[1] -> *(stack + 1)。
  特殊情况下,对数组名取地址,这个地址将指向整个数组,这与第一个元素的地址是一样的,但是指向的内存块大小不同。

int array[10];
cout<<array<<endl;  //输出 array[0] 的地址           类型为 int*            指针+1 导致 地址+4
cout<<&array<<endl; //输出 array 整个数组的地址      类型为 int(*)[10]      指针+1 导致 地址+4*10

注:默认 int为4字节。

  数组名与指针的区别:前者为常量不能修改,但可以使用sizeof查看数组长度,后者修改值代表指针指向地址的前后移动,而sizeof得到的是指针的长度。

3 指针与字符串
  C++多数表达式中,char数组名、char指针、字符串常量都被解释为字符串第一个字符的地址。要打印该地址,需要将地址量转换成(int*),否则将打印从第一个字符直至空字符。

C++11 :auto 与 decltype

  auto:自动类型推断,要求显示初始化,使得编译器能够将变量类型设置成初始值类型。一般用于复杂类型,在模板中常见,对于简单数据类型容易误用。
  decltype:将变量声明为表达式指定的类型。

    int y;
    decltype(y) x;  //定义x,使x的变量类型与y相同

  对于模板来说,只有实例化之后才能确定类型,因此decltype常用。

    template <typename T, typename U>
    void ef(T t , U u)
    {
        decltype(T*U) tu;
        //...
    }

Leave a Reply

Your email address will not be published. Required fields are marked *