栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

类型转换—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,%dn”, 1, 1.0);2

上代码:

#include
int main() {

    // 隐式类型转换(借助"=",因"="两边类型一致):
    //     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=%fn", 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=%fn", a1, a2, a3, a4, a5);
    
    double v = 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=%dn", 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("%dn", *(int*)p);
    printf("----------------------------------------------------------------------------n");
    
    return 0;
}
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
简述:将一个无符号短整型数从网络字节顺序转换为主机字节顺序。(16位)。
输入uint16_t netshort:一个以网络字节顺序表达的16位数。
返回值:uint16_t ntohs返回一个16位以主机字节顺序表达的数。
uint16_t ntohs(uint16_t netshort);

htons()
#include
uint16_t htons(uint16_t hostshort);

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

htonl()
#include
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 
using namespace std;

// const_cast 去掉const属性:
//     const_cast (&num),常用,因为函数调用时不能把一个const指针或应用直接赋给一个非const指针或引用,必须要转换。
//	   const_cast的目的并不是为了让你去修改一个本身被定义为const的值,因为这样做的后果是无法预期的。
//	   		const_cast的目的是修改一些指针/引用的权限,如果我们原本无法通过这些指针/引用修改某块内存的值,现在你可以了。

int main() {
	// const_cast的目的是修改一些指针/引用的权限
	int a = 100;
	
	const int *pi = &a;  
    int *pi2 = const_cast(pi);  
    
    *pi2 = 200;  
    cout << a << "," << *pi << "," << *pi2 <(b);  //编译通不过,不允许 
	
	// 去修改一个本身被定义为const的值,因为这样做的后果是无法预期的。
	const int c = 100;

	const int *p = &c;
    int *p2 = const_cast(p);  
      
    *p2 = 200;
    cout << c << "," << *p << "," << *p2 < 

static_cast:

// static_cast 静态类型转换。用于:
// 1. 基本数据类型转换。enum, struct, int, char, float等。
// 2. static_cast不能进行无关类型(如非基类和子类)指针之间的转换,通用指针void*可以。
// 3. 基类和子类之间转换:其中子类指针转换成父类指针是安全的;
// 		但父类指针转换成子类指针是不安全的。(基类和子类之间的动态类型转换建议用dynamic_cast)

int main() {

	int n = 6;
	int *pn = &n;

	double d = static_cast(n);  	 // 基本类型转换
	//double *d2 = static_cast(&n); // 无关类型指针转换,编译错误
	void *p = static_cast(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(pb); 			// 子类->父类,静态类型转换,正确但不推荐
	BaseClass *pd2 = dynamic_cast(pb); 		// 子类->父类,动态类型转换,正确

	BaseClass* pb2 =new BaseClass();
	DerivedClass *pd21 = static_cast(pb2);  // 父类->子类,静态类型转换,危险!访问子类m_szName成员越界
	DerivedClass *pd22 = dynamic_cast(pb2); // 父类->子类,动态类型转换,安全的。结果是NULL

	cout << pd21 << endl;	// res:0x1e1aa0
	cout << pd22 << endl;	// res:0

	// int a = 1;
	// int *pa = &a;
	// double *b = dynamic_cast(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(&doSomething); // 不同函数指针类型之间进行转换
	printf("---------------------------------------------------------n");

	int n = 6;
	int *pn = &n;

	double *d2 = reinterpret_cast(&n); // int*->double*
	void *p = reinterpret_cast(pn);      // int*->void*
	printf("%dn", *(int*)p);
	printf("----------------------------------------------------------n");
	
	//double d = reinterpret_cast(n);  	// int->double,编译错误!
	//char c = 127;
	//int d = reinterpret_cast(c);			// char->int,编译错误!
	
	printf("%dn", sizeof(int*));				// res:8
												// 64bit故用long long
	long long int p2 = reinterpret_cast(pn);
	int *p3 = reinterpret_cast(10);

	
	printf("llx:0x%llxn", p2);
	printf("llx:0x%llxn", p3);
}

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

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/883055.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号