考虑以下代码段:
char x[100];
double *p = &x;
如预期的那样,将产生以下警告:f.c:3:15: warning: initialization of ‘double *’ from incompatible pointer type ‘char (*)[100]’
[-Wincompatible-pointer-types]
3 | double *p = &x;
| ^
只需更改为double *p = (double*)&x;
我的问题是,类型转换真的有作用吗?如果不进行强制转换,代码将无效吗?还是仅仅是使编译器安静的一种方法?什么时候需要类型转换?我知道您可以对以下代码段产生一些影响:
int x = 666;
int y = (char)x;
但这不一样吗?int x = 666;
char c = x;
int y = c;
如果相同,则强制转换会执行某些操作,但这不是必需的。正确的?请帮助我理解这一点。
最佳答案
类型转换可以做几件不同的事情。正如其他答案所提到的,它几乎总是更改要转换的值的类型(或者可能是该类型的属性,例如const
)。它还可能以某种方式更改数值。但是有许多可能的解释:
另外,有时编译器尝试发出的警告,强制转换的沉默,无害和/或令人讨厌的内容,但有时它们是真实的,并且代码可能会失败(即,当沉默的警告正在尝试时告诉你)。
对于一些更具体的例子:
更改类型但不更改值的指针强制转换:
char *p1 = ... ;
const char *p2 = (const char *)p;
还有一个:unsigned char *p3 = (unsigned char *)p;
指针强制转换可以更显着地改变类型,但这可以保证(在某些架构上,它也可能会改变值):int i;
int *ip = &i;
char *p = (char *)ip;
同样重要的指针强制转换,但很可能不正确:char c;
char *cp = &c;
int *ip = (int *)cp;
*ip = 5; /* likely to fail */
指针强制转换毫无意义,即使使用显式强制转换,编译器也拒绝执行它:float f = 3.14;
char *p = (char)f; /* guaranteed to fail */
进行转换的指针强制转换,但无论如何编译器都将进行转换:int *p = (int *)malloc(sizeof(int));
(这被认为是一个坏主意,因为在您忘记包含<stdlib.h>
来声明malloc()
的情况下,强制转换可以使警告静音,从而警告您该问题。)由于C语言中一种非常特殊的特殊情况,从整数到指针的三个强制转换实际上是定义明确的:
void *p1 = (void *)0;
char *p2 = (void *)0;
int *p3 = (int *)0;
从整数到指针的两个强制转换不一定有效,尽管编译器通常会做一些显而易见的事情,并且强制转换将使否则的警告消失:int i = 123;
char *p1 = (char *)i;
char *p2 = (char *)124;
*p1 = 5; /* very likely to fail, except when */
*p2 = 7; /* doing embedded or OS programming */
从指针到int
的转换非常可疑:char *p = ... ;
int i = (int)p;
从指针到整数应该足够大的强制转换:char *p = ... ;
uintptr_t i = (uintptr_t)p;
强制转换会更改类型,但“丢弃”而不是“转换”值,并且使警告消失:(void)5;
进行数字转换的转换,但无论如何编译器都进行转换:float f = (float)0;
尽管通常不会更改位模式,但可以更改类型和解释值的转换:short int si = -32760;
unsigned short us = (unsigned short)si;
进行数字转换的转换,但是编译器可能会警告过的转换:int i = (int)1.5;
进行转换的编译器不会进行的转换:double third = (double)1 / 3;
最重要的是, Actor 绝对可以做事:其中一些有用,其中一些不必要但无害,其中一些危险。如今,许多C程序员之间的共识是,大多数强制转换是或应该是不必要的,这意味着避免显式强制转换是一个不错的规则,除非您确定自己知道自己在做什么,并且怀疑显式是合理的在其他人的代码中进行强制转换,因为这很可能是麻烦的征兆。
作为最后一个例子,就是这种情况,在过去,确实使灯泡在指针转换方面对我来说一直亮着:
char *loc;
int val;
int size;
/* ... */
switch(size) {
case 1: *loc += val; break;
case 2: *(int16_t *)loc += val; break;
case 4: *(int32_t *)loc += val; break;
}
loc += val
的这三个实例执行了三项完全不同的操作:一个更新一个字节,一个更新一个16位int,一个更新一个32位int。 (所讨论的代码是一个动态链接器,执行符号重定位。)
关于c - 类型转换实际上有什么作用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66001033/