C++的类型

2023-10-29

C++的类型

按照标准,C++只有两种类型:基本类型和复合类型,但是里面细节多导致彻底理解它们有难度,所以这里只是简单总结一下。

基本类型

基本类型分成算术类型和两种特殊的类型。

算术类型

算术类型分成整数类型和浮点数类型两种。

整数类型

以下都是整数类型:

有符号整数类型 无符号整数类型
标准整数类型 标准有符号整数类型 标准无符号整数类型
扩展整数类型 扩展有符号整数类型 扩展无符号整数类型

下面两个是属于上面的标准整数类型部分:

  • 标准有符号整数类型:signed char,short int,int,long int,long long int
  • 标准无符号整数类型:数量与标准有符号整数类型一一对应,除了signed char外直接在前面加关键字unsigned就得到对应的无符号整数类型,比如unsigned short int,不过这点标准文档没直说。

这份最小宽度表格抄自C++标准文档,顺便算了一下它们按照最小宽度能表示的范围的极限,其中long long表示范围比较大采用科学计数法表示。

类型 最小宽度N 有符号最小值 有符号最大值 无符号最大值
signed char 8 -128 127 256
short 16 -32768 32767 65536
int 16 -32768 32767 65536
long 32 -2147483648 2147483647 4294967296
long long 64 -9.22x10^18 9.22x10^18 1.84x10^19

一个具有宽度N的有符号整数类型的取值范围是,大于或等于-2^(N-1),小于或等于2^(N-1)-1;无符号整数类型对应是大于等于0,小于等于2^N

除了上面几个之外,下面这些也是整数类型,但是在标准里被单独罗列:

  • 普通字符类型:char,signed char,unsigned char。其中char类型是特殊的类型,由特定的编译器决定里面实际是signed char或是unsigned char
  • 窄字节字符类型:由普通字符类型和char8_t组成。char8_t隐藏类型是unsigned char
  • char16_tchar32_t,这两个也属于整数类型。(它们隐藏类型是uint_least16_tuint_least32_t,但是这两个隐藏类型不是整数类型)。
  • wchar_t类型。它是特殊的类型,宽字节字符,由特定编译器决定是有符号或者无符号整数,它能表示所有的国际长字节字符。
  • 类型bool,它是由编译器决定的无符号整数类型,取值范围是truefalse。它没有sign,unsigned,short,long这四种前缀。

整数类型示例

#include <iostream>

using namespace std;

int main() {
    int i;
    cout << "输出0到9:" << endl;
    for (i = 0; i < 10; i++) {
        cout << i << " ";
    }
    cout << endl;
    return 0;
}

输出:

输出0到9:
0 1 2 3 4 5 6 7 8 9 

演示bool

#include <iostream>

using namespace std;

int main() {
    char noticeTrue[] = "TRUE";
    char noticeFalse[] = "FALSE";
    bool condition = false;
    if (condition) {
        cout << noticeTrue << endl;
    } else {
        cout << noticeFalse << endl;
    }
    return 0;
}

输出:

$ ./a.out
FALSE

另外,标准规定了整数类型的最小值,最大值是没有限制的,所以实际上获取最小最大值结果可能是:

#include <iostream>

using namespace std;

int main() {
    cout << "type int ~ min=" << numeric_limits<int>::min() << endl;
    cout << "type int ~ max=" << numeric_limits<int>::max() << endl;
    return 0;
}

运行程序:

$ ./a.out
type int ~ min=-2147483648
type int ~ max=2147483647

跟除了C语言之外的其它高级编程语言相比,C++的整数类型比较复杂。在实际用的时候整数一般是用int类型定义,除非长度不够再换更大范围的。名字里面带有char字样的一般是定义成数组,用来存储字符串,UTF8编码的用char8_t,UTF16用char16_t,诸如此类。char类型比较特殊,除了ASCII编码的字符串外,涉及网络传输、文件读写等,需要一块区域做缓存的时候一般用char定义一块连续内存空间。bool用法就是存储真或者假,相当于别的编程语言的布尔类型。

浮点数类型

三种:float,double,long double,这三种中,后面的类型范围大于前面的类型范围。至于具体的范围是多大由具体的编译器决定。可以用std::numeric_limits类获取具体编译器上的最大、最小值(适用于整数、浮点数类型)。

浮点数类型使用示例

#include <iostream>

using namespace std;

int main() {
    float a, b, c;
    a = 1.01;
    b = 3.99;
    c = a * b;
    cout << "c=" << c << endl;
    return 0;
}

运行结果

c=4.0299

获取最大最小值示例(不同的机器上可能结果不一样)

#include <iostream>

using namespace std;

int main() {
    cout << "min=" << numeric_limits<long double>::min() << endl;
    cout << "max=" << numeric_limits<long double>::max() << endl;
    return 0;
}

运行结果

$ ./a.out
min=3.3621e-4932
max=1.18973e+4932

其它类型

除了算术类型之外的两种类型,在C++标准中这两个是单独作为两个类型来说明的。

  • cv void,使用CV限定符(constvolatile)修饰的void——也就是const voidvolatile void的统称,它跟void是不一样的
  • std::nullptr_t。命名空间std里面的nullptr_t类型。

复合类型

笼统地说,C++复合类型包括:

  • 数组
  • 函数
  • 引用
  • 类和结构体
  • 联合体
  • 枚举类型
  • 指针

数组

数组作用是存放相同类型的一组对象。数组声明方式:

类型 名称 [可选的常量表达式] 可选的其它限定符序列

例如下面的fibonacci就是一个数组:

#include <iostream>

using namespace std;

int main() {
    int i;
    int fibonacci[6] = {1, 1};
    cout << "计算前" << endl;
    for (i = 0; i < 6; i++) {
        cout << "i=" << i << ", value=" << fibonacci[i] << endl;
    }
    for (i = 2; i < 6; i++) {
        fibonacci[i] = fibonacci[i - 2] + fibonacci[i - 1];
    }
    cout << "计算后" << endl;
    for (i = 0; i < 6; i++) {
        cout << "i=" << i << ", value=" << fibonacci[i] << endl;
    }
    return 0;
}

运行程序将输出:

计算前
i=0, value=1
i=1, value=1
i=2, value=0
i=3, value=0
i=4, value=0
i=5, value=0
计算后
i=0, value=1
i=1, value=1
i=2, value=2
i=3, value=3
i=4, value=5
i=5, value=8

浮点数数组

#include <iostream>

using namespace std;

int main() {
    float x[] = {1.1, 2.2, 3.3}; // 初始化可以用 {} ,非初始化不能这样用
    for (int i = 0; i < 3; i++) {
        cout << "i=" << i << ", value=" << x[i] << endl;
    }
    return 0;
}

输出:

$ ./a.out
i=0, value=1.1
i=1, value=2.2
i=2, value=3.3

也可以声明多维数组,例如2维:

#include <iostream>

using namespace std;

int main() {
    int matrix[3][4];
    int i, j, n = 0;
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 4; j++) {
            matrix[i][j] = ++n;
        }
    }
    cout << "二维数组的内容:" << endl;
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 4; j++) {
            cout << "matrix(" << i << "," << j << ")=" << matrix[i][j] << "    ";
        }
        cout << endl;
    }
    return 0;
}

输出:

二维数组的内容:
matrix(0,0)=1    matrix(0,1)=2    matrix(0,2)=3    matrix(0,3)=4    
matrix(1,0)=5    matrix(1,1)=6    matrix(1,2)=7    matrix(1,3)=8    
matrix(2,0)=9    matrix(2,1)=10    matrix(2,2)=11    matrix(2,3)=12    

函数

C++中函数是一种类型,函数的名称可以当成变量名称用,能进行一些特定的操作。比如:

#include <iostream>

using namespace std;

int x (int a, int b);

int main() {
    int (*z) (int a, int b);
    z = &x;
    cout << (void *)&x << endl;
    cout << (void *)z << endl;
    cout << (*z)(3, 9) << endl;
    return 0;
}

int x (int a, int b) {
    return a + b;
}

* 运行结果,z保存的地址就是函数x的地址,于是(*z)就是函数x。

0x4008ec
0x4008ec
12

引用

如下,类型名称后面用符号&表示这是对应的引用类型:

#include <iostream>

using namespace std;

int main() {
    int x = 100;
    int& y = x; // y 引用了 x
    cout << "x=" << x << endl;
    cout << "y=" << y << endl; // 读取 y 就是读取 x
    y = 12; // 对 y 赋值就是对 x 赋值
    cout << "x=" << x << endl;
    cout << "y=" << y << endl;
    return 0;
}

输出:

x=100
y=100
x=12
y=12

类和结构体

标准中的描述是:包含一系列各种类型的对象、枚举和用于操纵这些对象的函数,以及对访问这些实体的一些限制。类是一种用途比较复杂的数据类型,这里简单做示例,更多内容单独整理一份文档。下面的class可以无缝替换为struct,它们都可用作定义类的关键字,其功能有点区别但是差不了多少。

#include <iostream>

using namespace std;

class Student {
public:
    Student(float age) {
        this->age = age;
    }
    void sayYourAge() {
        cout << "我今年" << age << "岁了。" << endl;
    }
private:
    float age;
};

int main() {
    Student xiaoMing = Student(14);
    Student xiaoWang = Student(17);
    xiaoMing.sayYourAge();
    xiaoWang.sayYourAge();
    return 0;
}

运行结果:

$ ./a.out
我今年14岁了。
我今年17岁了。

联合体

这里只简单介绍一下C++中的联合体unionunion能够在相同内存空间存储不同类型的对象。具体允许存入怎样的对象可以在定义时声明。在读取union中保存的对象时,按照什么方式读取决于访问成员。这是一个非常特殊的地方,也是联合的特征。另外,同struct一样,联合默认访问权限也是公有的,并且也具有成员函数。

#include <iostream>

using namespace std;

union Exams {
    float average;
    int   score;
    char  level;
};

int main() {
    Exams englishExams;
    englishExams.average = 76.342;
    englishExams.score = 80;
    englishExams.level = 'A'; // 由于union类型里面数据成员是保存进相同的地址,所以后面覆盖前面的,只有'A'是最终存进去的东西
    cout << "average=" << englishExams.average << "    地址:" << (void *)&(englishExams.average) << endl;
    cout << "score=" << englishExams.score << "    地址:" << (void *)&(englishExams.score) << endl;
    cout << "level=" << englishExams.level << "    地址:" << (void *)&(englishExams.level) << endl;
    return 0;
}

* 输出:

average=9.10844e-44    地址:0x7ffd15cee06c
score=65    地址:0x7ffd15cee06c
level=A    地址:0x7ffd15cee06c

枚举类型

枚举类型比较简单,它相当于给按顺序给自定义的常量赋予了自增值,也可以在定义时给需要枚举的常量指定一个值(值可以重复)。不能假设里面对应的值是int或者unsigned int类型,编译器会看情况选择更大范围的类型去存储。

用法:

#include <iostream>

enum Level {
    A = 100,
    B = 80,
    C = 60
};

int main() {
    Level exam = A;
    if (exam == A || exam == B) {
        std::cout << "还可以" << std::endl;
    } else {
        std::cout << "差" << std::endl;
    }
    return 0;
}

运行:

$ ./a.out
还可以

指针

  1. 指向任何对象的指针和指向const volatile voidconst voidvolatile void的指针都属于C++的复合类型。这种对象的类型称为“对象指针类型”,下面例子的a,b,x,y,z都是对象指针类型。
int main() {
    const void *x; // x 是复合类型
    volatile void *y; // y 是复合类型
    const volatile void *z; // z 是复合类型
    int* a; // 指向 int 类型的指针是复合类型
    float* b; // 指向 float 类型的指针是复合类型
    return 0;
}
  1. 具有类型的指向函数(包括类的静态成员)的指针。示例:
#include <iostream>

class Example {
public:
    static void sayHello() {
        std::cout << "你好啊,我是Example类的静态成员函数" << std::endl;
    }
};

void sayHello(); // 在main之前声明函数,当然也可以直接把函数定义在这里,效果相同

int main() {
    /* 声明pointerToSayHello是一个无参数且返回void类型的函数指针,
     * 并初始化其值为sayHello的地址。该函数指针指向的是普通的函数。
     */
    void (*pointerToSayHello)() = &sayHello;
    /* 声明pointerToExampleSayHello是一个无参数且返回void类型的函数指针,
     * 并初始化其值为Example::sayHello的地址。该函数指针指向的是静态成员函数。
     */
    void (*pointerToExampleSayHello)() = &(Example::sayHello);
    // 可以像调用函数一样执行:
    (*pointerToSayHello)();
    (*pointerToExampleSayHello)();
    return 0;
}

void sayHello() {
    std::cout << "你好啊" << std::endl;
}

* 运行的结果是:

$ ./a.out 
你好啊
你好啊,我是Example类的静态成员函数

注:指向对象结尾(如数组结尾)、空指针值或非法指针值的指针也算指针类型。指向cv void或者非cv void的指针可以用来指向不知道是什么类型的对象,这种指针能够容纳任何类型的对象指针,cv void *类型的对象具有跟cv char *类型的对象相同的表示和对齐特性。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++的类型 的相关文章

随机推荐

  • 五分钟搭建Jetbrains家族IDE授权服务器

    作为Java码农 IntelliJ IDEA可谓是N0 1的开发环境了 对框架的支持 界面 插件都是比较方便的 大大加快了开发的速度以及开发的乐趣 酷炫的界面也能大大的装一个逼 虽然这里教大家搭建授权服务器 但是月入1狗的同志还是支持一下人
  • LVGL学习笔记

    文章目录 前言 一 软件安装 1 VSCode安装 2 MSYS2安装 二 配置环境 1 添加环境变量 2 配置msys2环境 3 配置VSCode 三 运行lvgl示例 前言 最近需要使用LittlevGL 以下简称lvgl 做ARM开发
  • 比较C Sharp和Java

    本文对比C 与Java编程语言 因为这两种语言都具有自动垃圾回收以及运行时编译执行的特点 并且他们的语法都是继承自C语言 C 因此二者有个很多相似之处 但由于C 也被描述为一个C 和Java的混合体 并添加了一些新特性 引入了一些变化 因此
  • 记录el-form+el-dialog表单重置问题

    问题1 使用this refs formName resetFields 方法 表单无法重置 原因 resetField 方法不是将表单重置为空 而是重置为初始值 所以当我们打开新建表单的时候 表单项绑定的属性值为空 在提交表单后 表单项绑
  • 病毒分析教程第三话--静态逆向分析(上)

    静态逆向分析 上 教程参考自 恶意代码分析实战 程序来自 http www nostarch com malware htm 使用上两话静态特征分析和动态行为分析的方法只能从宏观的角度分析样本 但由于无法得到源代码 所以我们无法确凿地判定这
  • marquee 和JS 滚动效果

    一 marquee标签的几个重要属性 1 direction 滚动方向 包括4个值 up down left right 说明 up 从下向上滚动 down 从上向下滚动 left 从右向左滚动 right 从左向右滚动 语法
  • 解决LocalDateTime传值JSON格式化问题

    LocalDateTime是JDK8中提供的新功能 极大的优化了原生日期时间类的使用 但是第一次使用该类可能会在传值过程中出现格式化的小问题 如 JSON无法解析前端所传格式 序列化时LocalDateTime成为数组等 以下提供简单的解决
  • 移动开发 - Android - 实现两个页面(Activity)的简单跳转(Intent)

    我们要实现的页面跳转如下图所示 第一个页面 通过点击第一个按钮 实现跳转 通过点击第二个按钮实现跳转后 点击返回按钮 结束界面 因为之前的界面还没有结束 当第二个界面结束后 露出第一个界面 使用Intent实现页面的跳转有两种方式 1 无返
  • intel cpu 漏洞 linux,Intel CPU架构漏洞越捅越大:打补丁将损失30%性能

    还记得前不久那个被曝光影响大面积Intel Core CPU产品的安全漏洞吗 这貌似只是冰山一角 就在今天人们发现了Intel处理器里一个更为致命的漏洞 从最底端的Pentium 到最新的Coffee Lake Core 无一幸免 现在全球
  • nuxt打包后文件过大的优化

    在使用nuxt js来做项目的时候 遇到了加载缓慢的问题 解决思路如下 1 大文件拆分 2 文件压缩 大文件拆分 通过nuxt build analyze或者nuxt build a命令来启用 在package json中 添加 analy
  • TensorFlow Bug记录 CUBLAS_STATUS_NOT_INITIALIZED

    昨天刚装好也能运行的tensorflow突然之间报错 tensorflow stream executor cuda cuda blas cc 366 failed to create cublas handle CUBLAS STATUS
  • 虚拟服务器和vdi,VDI虚拟化平台搭建 01--VDI基本环境准备

    说明 此文章仅用于学习研究 不做任何商业用途 VDI 虚拟桌面基础架构 Virtual Desktop Infrastructure VDI基本软件硬件版本 服务器系统版本 exsi 6 7 vcenter版本 6 7 Vmware Hor
  • Typescript 基础类型 —— 布尔值 Boolean

    在JavaScript和TypeScript里布尔值都叫做boolean 表示逻辑值 true 和 false 关键字 boolean 实例 let isRes boolean false 编译结果 var isRes false 试图给
  • 【读懂Autosar代码】-1-概述

    点击返回 Autosar从入门到精通 实战篇 总目录 案例背景 共5页精讲 聊一聊这些封装中关键字宏的命名是如何构成的 FUNC FUNC P2CONST FUNC P2VAR P2VAR P2CONST CONSTP2VAR CONSTP
  • 论文期刊一般的审稿流程

    一 经常在网上看到某某人在问什么期刊的审稿周期 或者是投稿已多久怎么还没消息之类的帖子 作为经常帮国内外期刊审稿的人 对编辑部相对有所了解 因此特意发帖告知 供大家交流 论文审稿是个复杂的过程 并不是像大部分作者想象的那样送个一个专家看个几
  • String 判断字符串是否包含某个字符

    contains 判断 s 是否包含 ss 包含返回true 不包含返回false String s 你好 String ss 你 boolean ii s contains ss if ii true System out println
  • STM32调试特定函数出现Cannot access Memory

    MDK5出现Cannot access Memory 1 问题 2 原因 3 总结 1 问题 程序每次执行到了特定函数的位置时 keil里面全速运行 一直出现Cannot access Memory 再后面就是进入硬件错误中断了 执行到这个
  • C#使用COM+实现事务控制,操作多个数据库

    其中大部分内容参考自http blog itpub net 10752043 viewspace 991224 上面的是sqlserver的操作方式 因为我实际项目是用的oracle 就拿oracle试了一下 为了自己记录或者方便其他人 其
  • Linux下如何配置环境变量

    基础知识 首先 我们来了解一下什么是 环境变量 环境变量 通俗讲是操作系统或程序执行时候默认设定的参数 比如 PATH 路径变量 当要执行某个命令或程序的时候默认寻找的路径 然后 我们再来了解一下环境变量都有哪些类型 环境变量的分类 根据变
  • C++的类型

    C 的类型 按照标准 C 只有两种类型 基本类型和复合类型 但是里面细节多导致彻底理解它们有难度 所以这里只是简单总结一下 基本类型 基本类型分成算术类型和两种特殊的类型 算术类型 算术类型分成整数类型和浮点数类型两种 整数类型 以下都是整