• Cpp知识点系列-类型转换


    前言

    在做题的时候发现了需要用到类型转换,于是在这里进行了简单的记录。

    历史原因,慢慢整理着发现类型转换也能写老大一篇文章了。又花了时间来梳理一下就成了本文了。

    cpp

    之前使用的环境是DEV-C++ 5.4,而对应的GCC版本太低了。支持c++11需要GCC版本至少达到4.8.1才可以!

    1

    数据类型和运算符

    四种基本数据类型

    基本数据类型是分为四种的,分别是整型,浮点型,字符型和布尔型

    四种基本类型

    image-20201113122319295

    从表2-1中可以看到,C++的基本数据类型有bool(布尔型)、char(字符型)、 int(整型),float(浮点型,表示实数) , double(双精度浮点型,简称双精度型)。除了bool型外,主要有两大类:整数和浮点数。

    因为char型从本质上说也是整数类型,它是长度为1个字节的整数,通常用来存放字符的ASCII码。

    其中关键字signed和 unsigned,以及关键字short 和long被称为修饰符

    细节ISOC++标准并没有明确规定每种数据类型的字节数和取值范围,它只是规定它们之间的字节数大小顺序满足:

    (signed/unsigned)char ≤ (unsigned)short ≤ (unsigned)int ≤ (unsignedlong
    

    不同的编译器对此会有不同的实现。

    面向32位处理器(IA-32)的C++编译器,通常将intlong两种数据类型皆用4个字节表示。

    但一些面向64位处理器(IA-64或x86-64)的C++编译器中, int也是用4个字节表示, 但是long8个字节表示。

    结构体类型

    1. struct A {
    2.  char c1;
    3.  short s1;
    4. };

    这里不是主要说这个应用,而是分配字节的大小问题。

    基础数据类型的字节长度很明显:

    类型长度(字节)
    char1
    short2
    int4
    long4
    float4
    double8
    long long8

    然而,结构体的计算方式不是类似数组类型那样简单的累计,而是需要考虑到系统在存储结构体变量时的地址对齐问题

    偏移量概念:偏移量指的是结构体变量中成员的地址和结构体变量地址的差

    在实际中,存储变量时地址要求对齐,编译器在编译程序时会遵循两条原则

    (1)结构体变量中某成员的偏移量必须是该成员字长大小的整数倍(0被认为是任何数的整数倍)

    (2)结构体大小必须是所有成员大小的公倍数。(按顺序以已经存在的最大字长为单位)

    结构体大小等于最后一个成员的偏移量加上最后一个成员的大小

    故而有以下几个例子:

    1. struct A {
    2.  char c1;//偏移量0 字长1
    3.  char c2;//0+1=1 1
    4.  double d1;//1+1=2+6=8 8
    5.  //8+8=1618的公倍数
    6. };
    7. struct B {
    8.  char c1;//0 1
    9.  double d1;//1+7=8 8
    10.  char c2;//8+8=16  1
    11.  //16+1=17不是18的公倍数,要扩到24才是
    12. };
    13. struct C {
    14.  char c1;//0 1
    15.  float f1;//1+3 4
    16.  char c2;//8 1
    17.  //8+1=9不是14的公倍数,扩到12才是
    18. };

    枚举类型

    其实枚举类型的应用是很简单的,不过我个人应用的话更倾向于使用map类。

    类似结构体的语法。

    enum 枚举类型名 {变量值列表};
    

    附上例子。

    1. #include <iostream>
    2. using namespace std;
    3. enum GameResult {
    4.     WIN,LOSE,TIE,CANCEL
    5. }; //下标依次为0,1,2,3
    6. int main() {
    7.     GameResult result;//声明变量时,可以不写关键字enum
    8.     enum GameResult omit = CANCEL;//也可以在类型名前写enum
    9.     for (int count = WIN; count <= CANCELcount++) {//枚举类型隐含类型转换为整型
    10.         result = GameResult(count);//整型显式类型转换为枚举类型
    11.         if (result == omit)
    12.             cout << "The game was cancelled" << endl;
    13.         else {
    14.             cout << "The game was played ";
    15.             if (result == WIN)
    16.                 cout << "and we won ! ";
    17.             if (result == LOSE)
    18.                 cout << "and we lost . ";
    19.             cout << endl;
    20.         }
    21.     }
    22.     return 0;
    23. }

    注意:

    WIN等是常量,不能对它们赋值。作用范围(严格来说是 main() 函数内部)内不能再定义与它们名字相同的变量。

    枚举和宏其实非常类似:宏在预处理阶段将名字替换成对应的值(cpp->.i),枚举在编译阶段将名字替换成对应的值(.i->.s)。所以不能对枚举类型使用指针

    可以再复习一下CPP编译运行的过程就更容易理解了。

    ASCII表

    建议直接访问在线网页:https://zh.cppreference.com/w/cpp/language/ascii

    有以下四个需要注意:

    • 空格 32

    • ‘0’ 48

    • ‘A’ 65

    • ‘a’ 97

      image-20201113125805916

    运算符优先级

    优先级运算符说明结合性
    1::范围解析(命名空间)自左向右
    2++ --后缀自增/后缀自减
    ()括号
    []数组下标
    .成员选择(对象)
    −>成员选择(指针)
    3++ --前缀自增/前缀自减自右向左
    + −加/减
    ! ~逻辑非/按位取反
    (type)强制类型转换
    *取指针指向的值
    &某某的地址
    sizeof某某的大小
    new, new[]动态内存分配/动态数组内存分配
    delete, delete[]动态内存释放/动态数组内存释放
    4.* ->*成员对象选择/成员指针选择自左向右
    5* / %乘法/除法/取余
    6+ −加号/减号
    7<< >>位左移/位右移
    8< <=小于/小于等于
    > >=大于/大于等于
    9== !=等于/不等于
    10&按位与
    11^按位异或
    12|按位或
    13&&与运算
    14||或运算
    15?:三目运算符自右向左
    16=赋值
    += −=相加后赋值/相减后赋值
    *= /= %=相乘后赋值/相除后赋值/取余后赋值
    <<= >>=位左移赋值/位右移赋值
    &= ^= |=位与运算后赋值/位异或运算后赋值/位或运算后赋值
    17throw抛出异常
    18逗号自左向右

    关系运算符

    image-20201113140859803

    逻辑运算符

    操作数在计算之前隐式转换为类型 bool,结果的类型为 bool。

    非!

    使用方式为从右向左

    如果已转换的操作数是 false,则结果是 true;

    如果已转换的操作数是 true,则结果是 false。

    与&&

    使用方式为从左至右。

    如果所有的操作数都为 true,则逻辑“与”运算符 (&&) 返回布尔值 true,否则返回 false。

    第一个操作数将完全计算,并且完成所有副作用,之后才会继续计算下一个逻辑“与”表达式。

    如果第一个操作数的计算结果为 true(非零),才计算第二个操作数。

    或||

    使用方式为从左至右。

    如果任一操作数为 true,则逻辑“或”运算符 (||) 返回布尔值 true;否则返回 false。

    第一个操作数将完全计算,并且完成所有副作用,之后才会继续计算下一个逻辑“或”表达式。

    仅当第一个操作数的计算结果为 false (0) 时,才计算第二个操作数。

    算术运算符

    加减乘除

    • 当两个数都是整数时,运算结果也是整数。

    • 当有一个数是小数时,运算结果是小数。

    • 对于除法,如果两个整数相除但又不能整除,则只保留整数部分,这跟将小数赋值给整数类型是一个道理。

    取余

    “%”是取余运算,只能用于整型操作数,表达式a%b的结果是a被b除的余数。“%”的优先级与“/”相同。

    逗号运算符

    在C++中,逗号也是一个运算符,它的使用形式为:表达式1,表达式2 求解顺序为先求解i,再求解⒉,最终结果为表达式2的值。

    1. int x=0;
    2. int y=(x=x+3,4,545);
    3. cout<<y<<" "<<x;
    4. // 545 3

    结果是545 3

    类型转换

    C++基本类型(int,char等)的指针之间不能含有隐式转换,必须要用显示转换!

    int类型四舍五入

    因为题目要求保留一位有效数字,所以就先把这个数乘十,按照正负加减零点五,两次强制类型转换后,再除以十即可。今后碰见四舍五入问题以此类推!

    1. double dou=39.65;
    2. dou = (double)((int)(dou*10 + (dou<0?-0.5:0.5)))/10;

    int和char

    int转char之前,先将运算式中的每个字符都转换成ASCII码值,再进行计算,根据结果转换为字符(数值为该字符对应的ASCII码值)。

    以下代码为例,其中c4的结果符合我们的预期要求。

    1. void int_to_char(){
    2.     int i = 5;
    3.     char c1 = i;                  // 5 '\x05'无法打印
    4.     char c2 = i - 0;              // 5 '\x05'无法打印
    5.     char c3 = i - '0';            // -43 '\xd5'打印乱码
    6.     char c4 = i + '0';            // 53 '5'可打印
    7.     cout<<c4;
    8. }

    char转int之前,先将运算式中的每个字符都转换成ASCII码值,再进行计算。

    以下代码为例,其中i3的结果符合我们的预期要求。

    1. void char_to_int(){
    2.     char c = '0';
    3.     int i1 = c;                    // 48
    4.     int i2 = c - 0;                // 48
    5.     int i3 = c - '0';              // 0
    6.     int i4 = c + '0';              // 96
    7.     cout<<i3;
    8. }

    int和string

    1. void int_to_string() {
    2.     int a = 100;
    3.     string b = "";
    4.     b = to_string(a);//string库,但需要c++11的支持
    5.     cout<<b;
    6. }

    活着是另外一个方式

    1. void string_to_int() {
    2.     int a = 1;
    3.     string b = "100abbc";
    4.     a = atoi(b.c_str());//标准库,但是会忽略字符串中的字母,只保留数字
    5.     cout<<a<<endl;
    6.     a = stoi(b);//string库,但需要c++11的支持
    7.     cout<<a;
    8. }

    如果不支持c++11的话,可以参考博客

    1. #include<sstream>
    2. #include<string>
    3. int a = 10;
    4. stringstream ss;
    5. ss.str("");//重复调用一个对象的话要清空,clear函数只是重置状态。
    6. ss << a;
    7. string str = ss.str();

    int和bool

    int和bool类型之间存在隐式转换.

    注意,直接输出bool类型的时候,控制台上结果为1或0

    需要加上一个标志符来输出true或者false

    1. void bool_to_int() {
    2.     bool a = true, b = false;
    3.     cout << "a=" << a << " , b=" << b << endl;
    4.     cout << "a=" << boolalpha << a << " , b=" << b << endl;
    5. }

    image-20220828230919429

    string、char *、char[]

    string转char*

    主要有三种方法可以将string转换为const char*类型,分别是:data()、c_str()、copy()。

    • data()方法

    1. void stringt_to_char_data() {
    2.     string str = "hello";
    3.     const char *p1 = str.data();//不可修改
    4.     cout << p1 << endl;
    5.     char *p2 = (char *) str.data();//可修改
    6.     p2[1]++;
    7.     cout << p2;
    8. }
    • c_str()方法

    1. void stringt_to_char_c_str() {
    2.     string str="world";
    3.     const char *p1 = str.c_str();//不可修改
    4.     cout << p1 << endl;
    5.     char * p2=(char*)str.c_str();//可修改
    6.     p2[1]++;
    7.     cout << p2;
    8. }
    • copy()方法

      可能会报安全性错误,自行解决即可。注意手动加结束符!!!

    1. void stringt_to_char_copy() {
    2.     string str = "hmmm";
    3.     char p[10];
    4.     str.copy(p, 30);//这里3代表复制几个字符,0代表复制的位置,
    5.     p[3= '\0';//注意手动加结束符!!!
    6.     cout << p;
    7. }

    char * 转string

    可以直接赋值。

    1. string s;
    2. char *= "helloworld";
    3. = p;

    string转char[]

    for循环遍历输入。

    1. string pp = "helloworld";
    2. char p[20];
    3. int i;
    4. for( i=0;i<pp.length();i++)
    5.     p[i] = pp[i];
    6. p[i] = '\0';                  //手动添加结束符

    char[]转string

    可以直接赋值。

    1. string s;
    2. char p[20= "helloworld";
    3. = p;

    char[]转char*

    可以直接赋值。

    1. char pp[20= "helloworld";
    2. char* p = pp;
    3. 12

    char*转char[]

    主要有两种方法可以将char*转换为char[]类型,分别是:strcpy()、循环遍历。

    • strcpy()方法

    可能会报安全性错误,自行解决即可。

    1. char arr[20];
    2. char* tmp = "helloworld";
    3. strcpy(arr, tmp);
    • 循环遍历

    1. char arr[20];
    2. char* tmp = "helloworld";
    3. int i = 0;
    4. while (*tmp != '\0')
    5.  arr[i++= *tmp++;
    6. arr[i] = '\0';             //手动添加结束符

    进制转换

    1. int main() {
    2.     int PrintVal = 9;
    3.     /*按整型输出,默认右对齐*/
    4.     printf("%d\n", PrintVal);
    5.     /*按整型输出,补齐4位的宽度,补齐位为空格,默认右对齐*/
    6.     printf("%4d\n", PrintVal);
    7.     /*按整形输出,补齐4位的宽度,补齐位为0,默认右对齐*/
    8.     printf("%04d\n", PrintVal);
    9.     /*16进制输出,默认右对齐*/
    10.     printf("%x\n", PrintVal);
    11.     /*16进制输出,补齐4位的宽度,补齐位为空格,默认右对齐*/
    12.     printf("%4x\n", PrintVal);
    13.     /*按照16进制输出,补齐4位的宽度,补齐位为0,默认右对齐*/
    14.     printf("%04x\n", PrintVal);
    15.     /*8进制输出,默认右对齐*/
    16.     printf("%o\n", PrintVal);
    17.     /*8进制输出,补齐4位的宽度,补齐位为空格,默认右对齐*/
    18.     printf("%4o\n", PrintVal);
    19.     /*按照8进制输出,补齐4位的宽度,补齐位为0,默认右对齐*/
    20.     printf("%04o\n", PrintVal);
    21.     return 0;
    22. }

    结果如下:

    例子

    运算符例子1

    1. #include <iostream>
    2. #define endl '\n'
    3. using namespace std;
    4. int main() {
    5.     int a, b, c, x, y;
    6.     a = 1;
    7.     b = 2;
    8.     c = 0;
    9.     cout << a++ - 1 << endl;//后缀自增运算符优先级大于加减运算符 
    10.     cout << (a && b || !c) << endl;//a和b相与结果为真 
    11.     cout << b / ++<< endl;//2除以30 
    12.     x = ++a || ++&& ++c;//或运算被a=4短路 
    13.     cout << a << b << c << x << endl;
    14.     a = b = c = -1;
    15.     y = ++&& ++&& ++c;//与运算被a=0短路 
    16.     cout << a << b << c << y << endl;
    17.     return 0;
    18. }

    image-20201113103823373

    运算符例子2

    1. int main() {
    2.     int a = 4, b=3,c=2,d=1;
    3.     int x, y = 0;
    4.     x=a<b ? a+1 : c<d ? c+1 : d+1;//先判断a<b,再判断c<d,最后返回d+1 
    5.     cout <<<<endl;
    6.     cout <<(a+ b, b + c,c+ d) <<endl;//返回最后一个c+d
    7.     y += a+=b+= c+ d;//从右向左 
    8.     cout<<y<<endl;
    9.     return 0;
    10. }

    image-20201113114428361

    感谢

    源码文件

    gitee:https://gitee.com/JunKuangKuang/KeenCPPTest-all/tree/main/basic/transition

    github:https://github.com/JunKuangKuang/KeenCPPTest-all/tree/main/basic/transition

    更新记录

    2022.8.28更新:clang-1316.0.21.2.5,诶嘿嘿嘿……

    忘了啥时候更新的了:重新使用了TDM-GCC 9.2 真香!

    更早以前:后来我重新下载了新版本的,GCC更新为4.9的了。现在不让下载4.9的版本了,又重新下载了6版本使用。

    感谢

    感谢现在努力的我

    1. 参考《C++语言程序设计(第4版)》(郑莉,董渊)

    2. C++ int转string的多种方式

    3. c++中int与char相互转换

    4. printf按8进制、10进制、16进制输出以及高位补0

    5. C++逻辑运算符基本用法整理

    6. C++运算符优先级表

    7. c++中string、char *、char相互转换

    8. C++解决sizeof求结构体大小的问题

    9. C语言枚举类型

  • 相关阅读:
    LabVIEW安装了哪些版本的LabVIEW运行引擎
    MOCK远程API调用的简单实现
    kaggle新赛:AI Village夺旗赛挑战
    CA周记 - 带你进⼊ OpenAI 的世界
    java线程池详解
    Linux 环境搭建以及xshell远程连接
    Nginx-动静分离与 URLRwrite
    查询不为空的字段
    无人驾驶压路的应用之研华工控机ARK-1123助力
    Go语言类型与接口的关系
  • 原文地址:https://blog.csdn.net/qq_41461536/article/details/128089286