news 2026/1/11 14:36:49

类型转换—c、c++总结

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
类型转换—c、c++总结

目录

  • 前言
  • 1. c的类型转换
    • 1.1 隐式类型转换
    • 1.2 强制类型转换
    • 1.3 类型转换的函数
      • 1.3.1 字符串转实型:atoi(),strtol()等
      • 1.3.2 实型转字符串:sprintf()
      • 1.3.3 网络字节序转换函数:ntohs(),htons()
  • 2. C++的类型转换

前言

什么是隐式类型转换?什么时候会发生?那些类型可以隐式转换?强制类型转换什么情况必须用?c++与类型转换的4种关键字分别是什么,有什么区别和联系,各在什么场合下使用?等。
本文针对以上问题做简要小结。

同时会涉及到以下内容:
关于printf输出格式与类型不一致,请查看《%d输出float类型,%f输出int类型》
关于符号扩展,有符号与无符号的转换问题,请查看《符号位扩展,空间不足—char和int举例》


1. c的类型转换

1.1 隐式类型转换

隐式类型转换(自动类型转换)的发生:
一.借助"=“,因"="两边类型一致
二.函数调用,传参或返回时(实际上也是借助”=")
三.能够隐式转换的类型:
1.基本数据类型之间
如:int和double(double->int:可能出现丢失精度的问题)
int和char(int->char:可能出现空间不足,取低位,丢失高位数据1;char->int:会符号位扩展1);
2.通用指针。因所有类型的指针都可转化为通用指针,通用指针也可转化为任意类型的指针

注意:输出格式与类型不一致,不会发生隐式类型转换
如:printf(“%f,%d\n”, 1, 1.0);2

上代码:

#include<stdio.h>intmain(){// 隐式类型转换(借助"=",因"="两边类型一致): // double->int 丢失精度 // int->double float PI=3.14159;int s1, r=5;double s2;s1=r * r * PI;// 隐式转换,double->int 丢失精度 s2=r * r * PI;printf("s1=%d, s2=%f\n", s1, s2);int a=5;double a1=a/2;// 隐式类型转化,int—>double double a2=2;// 隐式类型转化,int—>double double a3=(double)2;// 强制类型转换,int->double;一般采取此种写法 double a4=(double)a/2;double a5=a/2.0;printf("a1=%f,a2=%f,a3=%f,a4=%f,a5=%f\n", a1, a2, a3, a4, a5);doublev=5.0;int v1=5/2;int v2=5.0/2;// 隐式类型转换,double->int 丢失精度 int v3=2.5;// 隐式类型转换,double->int int v4=(int)2.5;// 强制类型转换,double->int 丢失精度 printf("v1=%d, v2=%d, v3=%d, v4=%d\n", v1, v2, v3, v4);printf("--------------------------------------------------------------------------\n");// 隐式类型转换(借助"=",因"="两边类型一致): // 任何类型的指针->void* // void*->任何类型的指针 int c=1;int *p_int=&c;void *p=p_int;// 通用指针,可以隐式转换 void *p2=(void*)p_int;// 一般采取强制类型转化的写法 //p_double=p_int;// 不可以隐式转换,编译过不了 printf("%d\n", *(int*)p);printf("----------------------------------------------------------------------------\n");return0;}

1.2 强制类型转换

强制类型转换的格式为:(type_name) expression

写法上,"="两边一般都是强制类型转化的写法(即便是可以隐式转换的类型,不写强转也没错,但不建议):
1.直观上看,两边类型一致,易读易懂
2.避免出错,因为隐式类型转换只发生在如上所述的某些类型之间,其余的类型必须用强制类型转换,不然编译出错

1.3 类型转换的函数

1.3.1 字符串转实型:atoi(),strtol()等

一般都是数字的字符串,如:“178666”->178666

atoi为代表的:
char* 字符串转换int
int atoi(const char* nptr);

char* 字符串转换long
long atol(const char* nptr);

char* 字符串转换long long
long long atoll(const char *nptr);

char* 字符串转换float
double atof(const char *nptr);

strtol为代表的:
char* 字符串转换 unsigned long int
unsigned long int strtoul(const char *nptr, char **endptr, int base);

char* 字符串转换 unsigned long long int
unsigned long long int strtoull(const char *nptr, char **endptr, int base);

char* 字符串转换 long int
long int strtol(const char *nptr, char **endptr, int base);

char* 字符串转换 long long int
long long int strtoll(const char *nptr, char **endptr, int base);

char* 字符串转换 double
double strtod(const char *nptr, char **endptr);

char* 字符串转换 float
float strtof(const char *nptr, char **endptr);

char* 字符串转换 long double
long double strtold(const char *nptr, char **endptr);

1.3.2 实型转字符串:sprintf()

1.3.3 网络字节序转换函数:ntohs(),htons()

ntohs()
#include <netinet/in.h>
简述:将一个无符号短整型数从网络字节顺序转换为主机字节顺序。(16位)。
输入uint16_t netshort:一个以网络字节顺序表达的16位数。
返回值:uint16_t ntohs返回一个16位以主机字节顺序表达的数。
uint16_t ntohs(uint16_t netshort);

htons()
#include <netinet/in.h>
uint16_t htons(uint16_t hostshort);

ntohl()
简述:将一个无符号长整形数从网络字节顺序转换为主机字节顺序。(32位
输入uint32_t netlong:一个以主机字节顺序表达的32位数。
返回值:uint32_t ntohl返回一个32位以网络字节顺序表达的数。
#include <netinet/in.h>
uint32_t ntohl(uint32_t netlong);

htonl()
#include <netinet/in.h>
uint32_t htonl(uint32_t hostlong);


2. C++的类型转换

C++向下兼容C,故C的隐式类型转换,强制类型转换,和类型转换的一些函数在C++里同样适应

C++特有的,4种与类型转换相关的关键字。用法小结:
1.const_cast
常量指针或常量引用去const属性
2.static_cast(可以进行比特位上的转换)
基本数据类型之间的转换
3.dynamic_cast(基类必须有虚函数)
安全的基类指针和派生类指针之间转换。
4.reinterpret_cast(不可以进行比特位上的转换)
指针类型的转换

上代码:
const_cast:

#include <iostream>using namespace std;// const_cast 去掉const属性: // const_cast<int*>(&num),常用,因为函数调用时不能把一个const指针或应用直接赋给一个非const指针或引用,必须要转换。 // const_cast的目的并不是为了让你去修改一个本身被定义为const的值,因为这样做的后果是无法预期的。 // const_cast的目的是修改一些指针/引用的权限,如果我们原本无法通过这些指针/引用修改某块内存的值,现在你可以了。 intmain(){// const_cast的目的是修改一些指针/引用的权限 int a=100;const int *pi=&a;int *pi2=const_cast<int *>(pi);*pi2=200;cout<<a<<","<<*pi<<","<<*pi2<<endl;// res:200,200,200 printf("-----------------------------------------------------\n");// const int b=1;// int b2=const_cast<int>(b);//编译通不过,不允许 // 去修改一个本身被定义为const的值,因为这样做的后果是无法预期的。 const int c=100;const int *p=&c;int *p2=const_cast<int *>(p);*p2=200;cout<<c<<","<<*p<<","<<*p2<<endl;// res:100,200,200return0;}

static_cast:

// static_cast 静态类型转换。用于: //1. 基本数据类型转换。enum, struct, int, char, float等。 //2. static_cast不能进行无关类型(如非基类和子类)指针之间的转换,通用指针void*可以。 //3. 基类和子类之间转换:其中子类指针转换成父类指针是安全的; // 但父类指针转换成子类指针是不安全的。(基类和子类之间的动态类型转换建议用dynamic_cast)intmain(){int n=6;int *pn=&n;double d=static_cast<double>(n);// 基本类型转换 //double *d2=static_cast<double*>(&n);// 无关类型指针转换,编译错误 void *p=static_cast<void*>(pn);// 任意类型转换成void类型}

dynamic_cast:

// dynamic_cast // 有条件转换,动态类型转换,运行时类型安全检查(转换失败返回NULL): // 1. 安全的基类指针和派生类指针之间转换。 // 2. 必须要有虚函数。 class BaseClass { public: int m_iNum; virtual void foo(){}; // 基类必须有虚函数。保持多态特性才能使用dynamic_cast }; class DerivedClass: public BaseClass { public: char*m_szName[100]; void bar(){}; }; int main() { DerivedClass * pb = new DerivedClass(); BaseClass *pd1 = static_cast<BaseClass *>(pb); // 子类->父类,静态类型转换,正确但不推荐 BaseClass *pd2 = dynamic_cast<BaseClass *>(pb); // 子类->父类,动态类型转换,正确 BaseClass* pb2 =new BaseClass(); DerivedClass *pd21 = static_cast<DerivedClass *>(pb2); // 父类->子类,静态类型转换,危险!访问子类m_szName成员越界 DerivedClass *pd22 = dynamic_cast<DerivedClass *>(pb2); // 父类->子类,动态类型转换,安全的。结果是NULL cout << pd21 << endl; // res:0x1e1aa0 cout << pd22 << endl; // res:0 // int a = 1; // int *pa = &a; // double *b = dynamic_cast<double*>(pa); //int*->double*,编译错误! }

reinterpret_cast:

// reinterpret_cast // 1. 转换的类型必须是一个指针、引用、算术类型、函数指针或者成员指针。 // 2. 最普通的用途就是在函数指针类型之间进行转换。 // 3. 仅仅重新解释类型,它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针。 // 但不会进行比特位上的转换,如:不能int->double typedef void(*FuncPtr)(); int doSomething(){ return 0; }; int main() { FuncPtr funcPtrArray[10]; //funcPtrArray[0] = &doSomething; // 编译错误!类型不匹配,reinterpret_cast可以让编译器以你的方法去看待它们:funcPtrArray funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething); // 不同函数指针类型之间进行转换 printf("---------------------------------------------------------\n"); int n = 6; int *pn = &n; double *d2 = reinterpret_cast<double*>(&n); // int*->double* void *p = reinterpret_cast<void*>(pn); // int*->void* printf("%d\n", *(int*)p); printf("----------------------------------------------------------\n"); //double d = reinterpret_cast<double>(n); // int->double,编译错误! //char c = 127; //int d = reinterpret_cast<int>(c); // char->int,编译错误! printf("%d\n", sizeof(int*)); // res:8 // 64bit故用long long long long int p2 = reinterpret_cast<long long>(pn); int *p3 = reinterpret_cast<int*>(10); printf("llx:0x%llx\n", p2); printf("llx:0x%llx\n", p3); }

  1. 《符号位扩展,空间不足—char和int举例》 ↩︎ ↩︎

  2. 《%d输出float类型,%f输出int类型》 ↩︎

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/5 5:54:11

利用Miniconda管理多个PyTorch项目环境,避免依赖冲突

利用 Miniconda 管理多个 PyTorch 项目环境&#xff0c;避免依赖冲突 在深度学习项目开发中&#xff0c;一个看似不起眼却频繁“暴雷”的问题是什么&#xff1f;不是模型调参失败&#xff0c;也不是 GPU 显存不足&#xff0c;而是——“为什么你的代码能跑&#xff0c;我的就不…

作者头像 李华
网站建设 2026/1/9 18:48:32

一文搞懂大模型微调

前言 你是不是也有过这样的困惑&#xff1a;明明调用GPT、Llama这些大模型的API能解决通用问题&#xff0c;但一到自己的业务场景——比如让模型识别行业专属术语、生成符合公司风格的文案、处理特定格式的数据分析——效果就大打折扣&#xff1f;要么回答偏离需求&#xff0c;…

作者头像 李华
网站建设 2026/1/4 6:19:24

从Anaconda下载到PyTorch GPU运行:一站式操作手册

从Anaconda下载到PyTorch GPU运行&#xff1a;一站式操作手册 在深度学习项目中&#xff0c;最让人头疼的往往不是模型设计或调参&#xff0c;而是环境配置——明明代码没问题&#xff0c;却因为 torch.cuda.is_available() 返回 False 而卡住&#xff1b;或者换了台机器&…

作者头像 李华
网站建设 2026/1/4 0:50:18

清华镜像源配置教程:大幅提升Miniconda和pip安装速度

清华镜像源配置&#xff1a;加速 Miniconda 与 pip 安装的实战指南 在人工智能项目开发中&#xff0c;你是否经历过这样的场景&#xff1f;——深夜赶实验&#xff0c;运行 conda install pytorch 后盯着终端进度条一动不动&#xff0c;半小时过去只下载了 30%&#xff0c;最终…

作者头像 李华
网站建设 2026/1/3 23:19:26

从Anaconda到Miniconda:为何轻量级Python环境更适合AI研发

从Anaconda到Miniconda&#xff1a;为何轻量级Python环境更适合AI研发 在人工智能项目日益复杂的今天&#xff0c;你是否遇到过这样的场景&#xff1f;一个同事说“我的代码跑得好好的”&#xff0c;而你在本地却因为依赖版本不兼容、CUDA 驱动错配或某个包缺失而卡住数小时。更…

作者头像 李华
网站建设 2026/1/4 10:27:10

GitHub项目如何复现?Miniconda-Python3.10帮你锁定依赖版本

GitHub项目如何复现&#xff1f;Miniconda-Python3.10帮你锁定依赖版本 在人工智能和数据科学领域&#xff0c;你有没有遇到过这样的场景&#xff1a;从GitHub上克隆了一个热门开源项目&#xff0c;照着README一步步执行安装命令&#xff0c;结果却卡在某个包的版本冲突上&…

作者头像 李华