Cpp知识点系列-类型转换 c/c++类型转换的本质(经典之作)
liebian365 2024-10-20 09:57 31 浏览 0 评论
前言
在做题的时候发现了需要用到类型转换,于是在这里进行了简单的记录。
历史原因,慢慢整理着发现类型转换也能写老大一篇文章了。又花了时间来梳理一下就成了本文了。
之前使用的环境是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 ≤ (unsigned) long
不同的编译器对此会有不同的实现。
面向32位处理器(IA-32)的C++编译器,通常将int和long两种数据类型皆用4个字节表示。
但一些面向64位处理器(IA-64或x86-64)的C++编译器中, int也是用4个字节表示, 但是long 用8个字节表示。
结构体类型
struct A {
char c1;
short s1;
};
这里不是主要说这个应用,而是分配字节的大小问题。
基础数据类型的字节长度很明显:
类型长度(字节)char1short2int4long4float4double8long long8
然而,结构体的计算方式不是类似数组类型那样简单的累计,而是需要考虑到系统在存储结构体变量时的地址对齐问题
偏移量概念:偏移量指的是结构体变量中成员的地址和结构体变量地址的差。
在实际中,存储变量时地址要求对齐,编译器在编译程序时会遵循两条原则:
(1)结构体变量中某成员的偏移量必须是该成员字长大小的整数倍(0被认为是任何数的整数倍)
(2)结构体大小必须是所有成员大小的公倍数。(按顺序以已经存在的最大字长为单位)
结构体大小等于最后一个成员的偏移量加上最后一个成员的大小。
故而有以下几个例子:
struct A {
char c1;//偏移量0 字长1
char c2;//0+1=1 1
double d1;//(1+1=2)+6=8 8
//8+8=16是1,8的公倍数
};
struct B {
char c1;//0 1
double d1;//1+7=8 8
char c2;//8+8=16 1
//16+1=17不是1,8的公倍数,要扩到24才是
};
struct C {
char c1;//0 1
float f1;//1+3 4
char c2;//8 1
//8+1=9不是1,4的公倍数,扩到12才是
};
枚举类型
其实枚举类型的应用是很简单的,不过我个人应用的话更倾向于使用map类。
类似结构体的语法。
enum 枚举类型名 {变量值列表};
附上例子。
#include <iostream>
using namespace std;
enum GameResult {
WIN,LOSE,TIE,CANCEL
}; //下标依次为0,1,2,3
int main() {
GameResult result;//声明变量时,可以不写关键字enum
enum GameResult omit = CANCEL;//也可以在类型名前写enum
for (int count = WIN; count <= CANCEL; count++) {//枚举类型隐含类型转换为整型
result = GameResult(count);//整型显式类型转换为枚举类型
if (result == omit)
cout << "The game was cancelled" << endl;
else {
cout << "The game was played ";
if (result == WIN)
cout << "and we won ! ";
if (result == LOSE)
cout << "and we lost . ";
cout << endl;
}
}
return 0;
}
注意:
WIN等是常量,不能对它们赋值。作用范围(严格来说是 main() 函数内部)内不能再定义与它们名字相同的变量。
枚举和宏其实非常类似:宏在预处理阶段将名字替换成对应的值(cpp->.i),枚举在编译阶段将名字替换成对应的值(.i->.s)。所以不能对枚举类型使用指针!
可以再复习一下CPP编译运行的过程就更容易理解了。
ASCII表
建议直接访问在线网页:https://zh.cppreference.com/w/cpp/language/ascii
有以下四个需要注意:
- 空格 32
- ‘0’ 48
- ‘A’ 65
- ‘a’ 97image-20201113125805916
关系运算符
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的值。
int x=0;
int y=(x=x+3,4,545);
cout<<y<<" "<<x;
// 545 3
结果是545 3。
类型转换
C++基本类型(int,char等)的指针之间不能含有隐式转换,必须要用显示转换!
int类型四舍五入
因为题目要求保留一位有效数字,所以就先把这个数乘十,按照正负加减零点五,两次强制类型转换后,再除以十即可。今后碰见四舍五入问题以此类推!
double dou=39.65;
dou = (double)((int)(dou*10 + (dou<0?-0.5:0.5)))/10;
int和char
int转char之前,先将运算式中的每个字符都转换成ASCII码值,再进行计算,根据结果转换为字符(数值为该字符对应的ASCII码值)。
以下代码为例,其中c4的结果符合我们的预期要求。
void int_to_char(){
int i = 5;
char c1 = i; // 5 '\x05'无法打印
char c2 = i - 0; // 5 '\x05'无法打印
char c3 = i - '0'; // -43 '\xd5'打印乱码
char c4 = i + '0'; // 53 '5'可打印
cout<<c4;
}
char转int之前,先将运算式中的每个字符都转换成ASCII码值,再进行计算。
以下代码为例,其中i3的结果符合我们的预期要求。
void char_to_int(){
char c = '0';
int i1 = c; // 48
int i2 = c - 0; // 48
int i3 = c - '0'; // 0
int i4 = c + '0'; // 96
cout<<i3;
}
int和string
void int_to_string() {
int a = 100;
string b = "";
b = to_string(a);//string库,但需要c++11的支持
cout<<b;
}
活着是另外一个方式
void string_to_int() {
int a = 1;
string b = "100abbc";
a = atoi(b.c_str());//标准库,但是会忽略字符串中的字母,只保留数字
cout<<a<<endl;
a = stoi(b);//string库,但需要c++11的支持
cout<<a;
}
如果不支持c++11的话,可以参考博客。
#include<sstream>
#include<string>
int a = 10;
stringstream ss;
ss.str("");//重复调用一个对象的话要清空,clear函数只是重置状态。
ss << a;
string str = ss.str();
int和bool
int和bool类型之间存在隐式转换.
注意,直接输出bool类型的时候,控制台上结果为1或0
需要加上一个标志符来输出true或者false。
void bool_to_int() {
bool a = true, b = false;
cout << "a=" << a << " , b=" << b << endl;
cout << "a=" << boolalpha << a << " , b=" << b << endl;
}
image-20220828230919429
string、char *、char[]
string转char*
主要有三种方法可以将string转换为const char*类型,分别是:data()、c_str()、copy()。
- data()方法
void stringt_to_char_data() {
string str = "hello";
const char *p1 = str.data();//不可修改
cout << p1 << endl;
char *p2 = (char *) str.data();//可修改
p2[1]++;
cout << p2;
}
- c_str()方法
void stringt_to_char_c_str() {
string str="world";
const char *p1 = str.c_str();//不可修改
cout << p1 << endl;
char * p2=(char*)str.c_str();//可修改
p2[1]++;
cout << p2;
}
- copy()方法可能会报安全性错误,自行解决即可。注意手动加结束符!!!
void stringt_to_char_copy() {
string str = "hmmm";
char p[10];
str.copy(p, 3, 0);//这里3代表复制几个字符,0代表复制的位置,
p[3] = '\0';//注意手动加结束符!!!
cout << p;
}
char * 转string
可以直接赋值。
string s;
char *p = "helloworld";
s = p;
string转char[]
for循环遍历输入。
string pp = "helloworld";
char p[20];
int i;
for( i=0;i<pp.length();i++)
p[i] = pp[i];
p[i] = '\0'; //手动添加结束符
char[]转string
可以直接赋值。
string s;
char p[20] = "helloworld";
s = p;
char[]转char*
可以直接赋值。
char pp[20] = "helloworld";
char* p = pp;
12
char*转char[]
主要有两种方法可以将char*转换为char[]类型,分别是:strcpy()、循环遍历。
- strcpy()方法
可能会报安全性错误,自行解决即可。
char arr[20];
char* tmp = "helloworld";
strcpy(arr, tmp);
- 循环遍历
char arr[20];
char* tmp = "helloworld";
int i = 0;
while (*tmp != '\0')
arr[i++] = *tmp++;
arr[i] = '\0'; //手动添加结束符
进制转换
int main() {
int PrintVal = 9;
/*按整型输出,默认右对齐*/
printf("%d\n", PrintVal);
/*按整型输出,补齐4位的宽度,补齐位为空格,默认右对齐*/
printf("%4d\n", PrintVal);
/*按整形输出,补齐4位的宽度,补齐位为0,默认右对齐*/
printf("%04d\n", PrintVal);
/*按16进制输出,默认右对齐*/
printf("%x\n", PrintVal);
/*按16进制输出,补齐4位的宽度,补齐位为空格,默认右对齐*/
printf("%4x\n", PrintVal);
/*按照16进制输出,补齐4位的宽度,补齐位为0,默认右对齐*/
printf("%04x\n", PrintVal);
/*按8进制输出,默认右对齐*/
printf("%o\n", PrintVal);
/*按8进制输出,补齐4位的宽度,补齐位为空格,默认右对齐*/
printf("%4o\n", PrintVal);
/*按照8进制输出,补齐4位的宽度,补齐位为0,默认右对齐*/
printf("%04o\n", PrintVal);
return 0;
}
结果如下:
感谢
源码文件
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版本使用。
感谢
感谢现在努力的我
- 参考《C++语言程序设计(第4版)》(郑莉,董渊)
- C++ int转string的多种方式
- c++中int与char相互转换
- printf按8进制、10进制、16进制输出以及高位补0
- C++逻辑运算符基本用法整理
- C++运算符优先级表
- c++中string、char *、char相互转换
- C++解决sizeof求结构体大小的问题
- C语言枚举类型
相关推荐
- 月薪 4K 到 4W 的运维工程师都经历了什么?
-
运维工程师在前期是一个很苦逼的工作,在这期间可能干着修电脑、掐网线、搬机器的活,显得没地位!时间也很碎片化,各种零碎的琐事围绕着你,很难体现个人价值,渐渐的对行业很迷茫,觉得没什么发展前途。这些枯燥无...
- 计算机专业必须掌握的脚本开发语言—shell
-
提起Shell脚本很多都有了解,因为无论是windows的Dom命令行还是Linux的bash都是它的表现形式,但是很多人不知道它还有一门脚本编程语言,就是ShellScript,我们提起的Shel...
- Linux/Shell:排名第四的计算机关键技能
-
除了编程语言之外,要想找一份计算机相关的工作,还需要很多其他方面的技能。最近,来自美国求职公司Indeed的一份报告显示:在全美工作技能需求中,Linux/Shell技能仅次于SQL、Java、P...
- 使用Flask应用框架在Centos7.8系统上部署机器学习模型
-
安装centos7.8虚拟环境1、镜像链接...
- shell编程
-
简介:Shell是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言。...
- 14天shell脚本入门学习-第二天#脚本和参数#排版修正
-
脚本是一种包含一系列命令的文本文件,通常用于自动化任务。Shell脚本是用Shell命令编写的脚本,可以在命令行中执行。掌握脚本的基础知识和变量的使用是编写高效脚本的关键。...
- 嵌入式Linux开发教程:Linux Shell
-
本章重点介绍Linux的常用操作和命令。在介绍命令之前,先对Linux的Shell进行了简单介绍,然后按照大多数用户的使用习惯,对各种操作和相关命令进行了分类介绍。对相关命令的介绍都力求通俗易懂,都给...
- 实现SHELL中的列表和字典效果
-
大家好,我是博哥爱运维。编写代码,很多情况下我们需要有种类型来存储数据,在python中有列表和字典,golang中有切片slice和map,那么在shell中,我们能否实现列表和字典呢,答案是肯定的...
- 14天shell脚本入门学习-第二天#脚本和变量
-
脚本是一种包含一系列命令的文本文件,通常用于自动化任务。Shell脚本是用Shell命令编写的脚本,可以在命令行中执行。掌握脚本的基础知识和变量的使用是编写高效脚本的关键。...
- shell常用命令之awk用法介绍
-
一、awk介绍awk的强大之处,在于能生成强大的格式化报告。数据可以来自标准输入,一个或多个文件,或者其他命令的输出。他支持用户自定义函数和动态正则表达式等先进功能,是Linux/unix一个强大的文...
- Linux编程Shell之入门——Shell数组拼接与合并
-
在Shell中,可以使用不同的方式实现数组拼接和合并。数组拼接指将两个数组中的元素合并成一个数组,而数组合并指将两个数组逐个组合成一个新数组。以下是关于Shell数组拼接和合并的详细介绍:数...
- shell中如何逆序打印数组的内容,或者反转一个数组?
-
章节索引图首先请注意,有序的概念仅适用于索引数组,而不适用于关联数组。如果没有稀疏数组,答案会更简单,但是Bash的数组可以是稀疏的(非连续索引)。因此,我们需要引入一个额外的步骤。...
- 如何学好大数据开发?---shell基本语法
-
昨天我们初步了解到了shell的一些基本知识,比如shell的分类,常用的shell类型。今天就带来大数据开发之shell基本语法,掌握好基础才是最重要的,那接下来就开始学习shell的基本语法。一、...
- Linux编程Shell之入门——Shell关联数组
-
关联数组是Shell中一种特殊的数组类型,它使用字符串作为下标。在关联数组中,每个元素都被标识为一个唯一的字符串键值,也称为关联数组的索引。在Shell中,可以使用declare或typeset命令...
- 从编译器视角看数组和指针
-
虽然有单独的文章描述数组和指针,但二者的关系实在值得再写一篇文章。...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)