c语言转换

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 .data
x1: .long 10

.section .text
.globl main
main:
    movl $x1, %eax
    movl (%eax), %ebx
    pushl %ebx
    pushl $format
    call printf
    addl $8, %esp
    movl $0, %eax
    ret

.section .rodata
format: .string "%d\n"
整数转化为指针

整数转化为指针是可以的,但实际中应避免这种行为。除非有具体的规定,否则结果是有具体编译器实现的。将整数转化为指针可能会造成未对齐问题(3转化为指针,对齐要求数据的起始地址是2或4或8或16的整数倍),可能出现未指向一个有效实体。比如

int x = 10;//假设地址为0x1000
char* 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

c语言中,函数名代表了函数中指令开始的地址。函数指针转化,如果被转化的函数的返回值,入参与函数指针所返回的参数,入值参数不一样,那么可能出现未定义的错误。

#include <stdio.h>
double myfun1(void)
{
	double x = 1;
	printf("这是个小数");
	return x; 
}

float mufun2(int x)
{
	float z = x;
	printf("这是个整数");
	return z; 
}

int main(void)
{
	float (*xfun)(int) = mufun2;
	xfun(1);
	xfun = myfun1;
	xfun();
}

比如这段代码myfun1的形参和返回值与xfun不一样,导致编译错误,或者函数运行时产生未定义的错误。

参考资料:

A pointer to a function of one type may be converted to a pointer to a function of another
type and back again; the result shall compare equal to the original pointer. If a converted
pointer is used to call a function whose type is not compatible with the referenced type,
the behavior is undefined.

struct pointer

结构体指针进行转化。因为一些硬件平台有特定的对齐规则,如果指向的对象类型没有正确的指向,可能会出现未定义错误,如果再转化回来,应该跟原来一样;结构体指针转化为字符指针,那么这个字符指针指向这个结构体的最低地址。

所以可以把结构体指针转化为字符指针然后遍历结构体中的所有元素。

https://blog.csdn.net/qhairen/article/details/51766118

算术操作转换

使存储的数字能够按照同一种存储规则进行加减法运算。

算术隐式转换规则:

如果有浮点数,有long double全部转变为long double,否则有double转为double,否则有float全部转为float。

如果有整数,类型全部相同的不转换;如果有一个unsigned 类型的等级大于等于其他等级,那么全部转为unsigned类型。如果有不是unsigned的类型的等级高于其他等级,那么则转化为不是该unsigned的类型。

例子:

#include <stdio.h>

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。

  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值