c语言中转换按编译器是否自动转换可以分为隐式转换和强制转换,按对象与对象之间的转换可以分为指针,复数转实数等。
转换的目的是将某种类型x当成另一种类型y来使用,但是x还是x.
疑惑?c语言怎么看待?
int x = 99;void* p = 0x1000;p = (int*)p;
指针转换
c语言指针类型可以分为 void pointer,null pointer, qualifiled pointer(被const,volatile等修饰的指针), function pointer,structure pointer,普通变量指针等。
指针与整数
指针是一个变量,它的值是某个对象的地址值。下面两段代码一个是c语言程序,一个是该c语言程序可能所对应的汇编代码。
#include "stdio.h" int main(void){int x1 = 10;int* p1 = &x1;printf("%d",*p1);}
.section .datax1: .long 10.section .text.globl mainmain:movl $x1, %eaxmovl (%eax), %ebxpushl %ebxpushl $formatcall printfaddl $8, %espmovl $0, %eaxret.section .rodataformat: .string "%d\n"
整数转化为指针
整数转化为指针是可以的,但实际中应避免这种行为。除非有具体的规定,否则结果是有具体编译器实现的。将整数转化为指针可能会造成未对齐问题(3转化为指针,对齐要求数据的起始地址是2或4或8或16的整数倍),可能出现未指向一个有效实体。比如
int x = 10;//假设地址为0x1000char* p;p = 1000;
int数据的存储方式不同于char型;指针不仅告诉了编译器变量存储的地址,还让编译器明白了变量的使用方式(怎能读取,怎么清除,怎么进行运算等)。因此用p不能正确表示int型变量x,还可能让编译器出现崩溃。
参考英文:
An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation
指针转为整数
指针转化为整数是可能可以的,但实际中应该避免这种行为。具体的实现有编译器决定.而且如果地址的长度大于该类型整数的长度,出现的结果是未定义的。比如下段代码和下张图。
#include "stdio.h" #include "stdint.h"unsigned int* g(void) {unsigned int *ptr = 0xdeadbeeffff;/* ... */return ptr;} int main(void){unsigned int x;x = g();printf("%lx",x);}
参考段落
Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.
void 指针的转换
c语言规定void指针可以转化为任何类型来使用,任何类型也可以转为void类型来使用。
例子fat文件系统中的f_read函数。
FRESULT f_read (FIL *fp, /* Pointer to the file object */void *buff,/* Pointer to data buffer */UINT btr,/* Number of bytes to read */UINT *br/* Pointer to number of bytes read */){FRESULT res;DWORD clst, sect, remain;UINT rcnt, cc;BYTE *rbuff = buff;.........}
f_read(,buff,btr,br)。
buff为任何类型都可以,都可以转化为void类型,而void类型都可以转化为byte(unsigned char)类型,这样做语法上不会产生任何错误,但是比如buff是uint16_t*的话,数据是按照16位无符号整数进行存储的,但经过这样的转化,数据是按照8位的方式进行存储的,但用的时候是按照16位无符号整数进行使用,所以会造成错误。所以这样的用法造成数据失真。
参考段落
A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer
null指针
空指针是不指向任何地址的指针,c语言规定如果一个类型的指针赋值为这3中方式,那么该指针就为空指针。
int* x;x = 0;x = (void*)0;x = NULL;//这3中赋值方式都为空指针
如果一种类型的空指针被转化为另一类型的指针,那么就会产生另一类型的空指针,比如
#include "stdio.h" #include "stdint.h"int main(void){int* x ;x = NULL;printf("%d",sizeof(*x));printf("%d",sizeof(*((char*)x)));}
参考段落
An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. 66) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function. 4 Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.
qualified 指针
被const,volatile等修饰的类型的指针不能转化为没有被修饰的指针(可以的话常量被修改),而没有被这些关键字修饰的指针可以转化为被修饰的指针。
参考段落
For any qualifier q , a pointer to a non- q -qualified type may be converted to a pointer to the q -qualified version of the type; the values stored in the original and converted pointers shall compare equal.
function pointer
struct pointer
结构体对齐问题
结构体对齐问题以及强制类型转换问题总结_结构体强转问题-CSDN博客
算术操作转换
使存储的数字能够按照同一种存储规则进行加减法运算。
算术隐式转换规则:
如果有浮点数,有long double全部转变为long double,否则有double转为double,否则有float全部转为float。
如果有整数,类型全部相同的不转换;如果有一个unsigned 类型的等级大于等于其他等级,那么全部转为unsigned类型。如果有不是unsigned的类型的等级高于其他等级,那么则转化为不是该unsigned的类型。
例子:
#include int main(void){short int x1 = -1;unsigned short int x2 = x1;x2 = x2 + 1;printf("%d",x2);}
输出结果是0,原因是:
该环境short 类型有2字节,x1为short int,为-1,补码则是0xffff,那么转化为unsigned int就是65535,65535+1,unsigned溢出,那么就是0了。
float类型和相关表达式可能以超过该类型的精度和范围来表达float,但其实仍然你存储的是float。