进制转换和类型转换

版权声明:将不定期更新,如有任何疑问,欢迎留言!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! https://blog.csdn.net/essity/article/details/81984671

1 进制英文表示

  binary 二进制的
  octal 八进制的
  hexadecimal 十六进制的
  decimal 十进制的

2 C语言使用

  默认是10进制的;C,C++规定,一个数如果要指明是二进制的,开头加0b;一个数如果要指明它采用八进制,必须在它前面加上一个0,如:123是十进制,但0123则表示采用八进制;16进制数必须以 0x开头。

3 内部存储

  数据是由二进制补码存储的,第一位为符号位(1负,0正):
  1)当原码为正数的时候,正数的原码反码补码都相同,即00011的反码也为00011,补码也为00011。
  2)当原码为负数的时候,反码即按位取反,比如10011为原码,10011可表示-3,那么符号位不变,其余位按位取反即反码11100.那么10011的补码便是11101.

4 基本变量

4.1 基本类型变量

char%c、%d、%u)
short%hd)
int%d)
long%ld)
long long%lld)
//对应无符号类型
unsigned char%c、%d、%u)
unsigned short%hu、%ho、%hx)
unsigned int%u,%o、%x)
unsigned long%lu、%lo、%lx)
unsigned long long%llu、%llo、%llx)
//无符号类型打印出的值就是内存中存数的实际二进制值
float%f)
double%lf)
long double(%Lf)

4.2 符号扩展

  需要扩展的变量量为有符号数,扩展存储位数的方法,即在新的高位字节使用当前最高有效位即符号位的值进行填充。
  例1:

char a=0xff; //有符号值为-1,二进制为11111111,其中最高位为符号位
short b=a; //b的有符号值为-1,在内存中存储的值为1111111111111111

  例2:

char a=1; //有符号值为1,二进制为00000001,其中最高位为符号位
short b=a; //b的有符号值为1,在内存中存储的值为0000000000000001

4.3 零扩展

  对于要扩展量无符号数,扩展存储位数的方法。在新的高位直接填0。

unsigned char a=0xff;//二进制为11111111,所有值都是有效值
unsigned short b=a;//b经过零扩展后,内存中存储的值为0000000011111111

4.4 其他

  其实这里注重的是要扩展的量是有符号量还是无符号量。若要扩展量为有符号量,不管扩展成有符号还是无符号,都遵循符号扩展;若要扩展量为无符号量,不管扩展成有符号还是无符号,都遵循零扩展。
  例1:

char a =0xff;//a为-1,其为有符号量,二进制为11111111
unsigned shortb=a;//此处a要进行符号扩展,b的二进制为11111111 11111111

  例2:

unsigned char a=0xff;//a为无符号量,二进制为11111111
short b=a;//此处a要进行零扩展,b的二进制为00000000 11111111

5 类型转换

  C语言的类型转换,可以分为两种:自动类型转换(隐式类型转换,有编译器帮你去完成)强制类型转换(显示类型转换,你知道自己想要什么,所以才转换)

5.1 类型转换和扩展:

  一、有符号数的转换规则

方法
char short 符号位扩展
char long 符号位扩展
char unsigned char 最高位失去符号位意义,变为数据位
char unsigned short 符号位扩展到short;然后从short转到 unsigned short
char unsigned long 符号位扩展到long; 然后从long 转到unsigned long
char float 符号位扩展到long; 然后从long 转到float
char double 符号位扩展到long; 然后从long 转到double
char long double 符号位扩展到long; 然后从long 转到long double
short char 保留低位字节
short long 符号位扩展
short unsigned char 保留低位字节
short unsigned short 最高位失去符号位意义,变为数据位
short unsigned long 符号位扩展到long; 然后从long转到unsigned double
short float 符号位扩展到long; 然后从long 转到float
short double 符号位扩展到long; 然后从long 转到double
short long double 符号位扩展到long; 然后从long 转到double
long char 保留低位字节
long short 保留低位字节
long unsigned char 保留低位字节
long unsigned short 保留低位字节
long unsigned long 最高位失去符号位意义,变为数据位
long Float 使用单精度浮点数表示。可能丢失精度。
long double 使用双精度浮点数表示。可能丢失精度。
long long double 使用双精度浮点数表示。可能丢失精度。

  二、无符号数的转换规则

方法
unsigned char char 最高位作为符号位
unsigned char short 0扩展
unsigned char long 0扩展
unsigned char unsigned short 0扩展
unsigned char unsigned long 0扩展
unsigned char float 转换到long;再从 long 转换到float
unsigned char double 转换到long;再从 long 转换到double
unsigned char long double 转换到long;再从 long 转换到double
unsigned short char 保留低位字节
unsigned short short 最高位作为符号位
unsigned short long 0扩展
unsigned short unsigned char 保留低位字节
unsigned short unsigned long 0扩展
unsigned short float 转换到long;再从 long 转换到float
unsigned short double 转换到long;再从 long 转换到double
unsigned short long double 转换到long;再从 long 转换到double
unsigned long char 保留低位字节
unsigned long short 保留低位字节
unsigned long long 最高位作为符号位
unsigned long unsigned char 保留低位字节
unsigned long unsigned short 保留低位字节
unsigned long float 转换到long;再从 long 转换到float
unsigned long double 直接转换成double
unsigned long long double 转换到long;再从 long 转换到double

  总结:
  一、短数据类型扩展为长数据类型

  1. 要扩展的短数据类型为有符号数
      进行符号扩展,即短数据类型的符号位填充到长数据类型的高字节位(即比短数据类型多出的那一部分),保证扩展后的数值大小不变。
char x=0b10001001;
short y=x;
//则y的值应为11111111 10001001b;
char x=0b00001001;
short y=x;
//则y的值应为00000000 00001001b;
  1. 要扩展的短数据类型为无符号数
      进行零扩展,即用零来填充长数据类型的高字节位。
unsigned char x=0b10001001;
short y=x;
//则y的值应为00000000 10001001b;
unsigned char x=0b00001001;
short y=x;
//则y的值应为00000000 00001001b;

  二、长数据类型缩减为短数据类型
  如果长数据类型的高字节全为1或全为0,则会直接截取低字节赋给短数据类型;如果长数据类型的高字节不全为1或不全为0,则转会就会发生错误。
  三、同一长度的数据类型中有符号数与无符号数的相互转化
  直接将内存中的数据赋给要转化的类型,数值大小则会发生变化。另短类型扩展为长类型时,但短类型与长类型分属有符号数与无符号数时,则先按规则一进行类型的扩展,再按本规则直接将内存中的数值原封不动的赋给对方。

5.2 隐式转换原则

  变换操作数采取就高不就低的原则,即级别低的操作数先被转换成和级别高的操作数具有同一类型,然后再进行运算,结果的数据类型和级别高的操作数相同。且有符号的转换成无符号的。
高   double ←← float
↑    ↑
↑    long
↑    ↑
↑    unsigned
↑    ↑
低    int ←← char,short

5.3 结构、联合变量及其成员变量

  同类型的结构可以相互赋值:

typedef struct test{
	char*name;
    unsigned short age;
} Struct_test;
Struct_test a,b={“zhangsan”,20};
a = b;//a和b中的数据是一样的,但在不同的存储空间

  通过共用体来确定机器是大端序还是小端序的例子:
  大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。
  小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

#include <stdio.h>
union test {
	char a[4];
	int b;
};

int main(int argc, char **argv) {
	union test tst;
	tst.a[0] = 0x04;
	tst.a[1] = 0x03;
	tst.a[2] = 0x02;
	tst.a[3] = 0x01;
	printf("0x%x\n", tst.b);
	return 0;
}

  若打印出0x4030201则为大端序,若为0x1020304则为小端序

5.4 void **的转换

  C语言中没有通用指针类型,void *之所以可以用作通用指针,是因为当它和其他类型相互赋值的时候,如果需要,它可以自动转换成其他类型。但是,void **就不会自动转换了,原因是,当你使用void **指针的时候,例如用*操作符访问void **所指向的void *值得时候,编译器无法知道void *值是否从其他类型的指针转换而来,从而,编译器只能认为它仅仅是个void *指针,所以程序就无法正确访问到想要的结果。
  换言之,你使用的任何void **值必须是某个位置的void *值得地址,(void **)&dp这样的类型转化虽然能编译通过,但执行结果可能不是我们想要的。如果void **指针指向的不是void *类型,并且这个类型的大小和内存表示和void *也不同,则程序就无法正确访问到此类型。

6 C++隐式类型转换

6.1 原因

  C++面向对象的多态特性,就是通过父类的类型实现对子类的封装。通过隐式转换,你可以直接将一个子类的对象使用父类的类型进行返回。
  某些方面来说,隐式转换给C++程序开发者带来了不小的便捷。
  C++是一门强类型语言,类型的检查是非常严格的。如果没有类型的隐式转换,这将给程序开发者带来很多的不便。
  当然,凡事都有两面性,在你享受方便快捷的一面时,你不得不面对太过智能以至完全超出了你的控制。风险就在不知不觉间出现。

6.2 隐式调用构造函数

  当构造函数只有一个参数,或者含有默认参数的时候,且参数类型为内建类型时,可以不用显示调用构造函数。

文章链接

【csapp】【微软面试题】有符号数到无符号数隐式转换:https://blog.csdn.net/u012162613/article/details/40887457

猜你喜欢

转载自blog.csdn.net/essity/article/details/81984671