铸造实际上有什么作用吗? [英] Does casting actually DO anything?

查看:45
本文介绍了铸造实际上有什么作用吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下代码段:

char x[100];
double *p = &x;

如预期的那样,将产生以下警告:

As expected, this yields this warning:

f.c:3:15: warning: initialization of ‘double *’ from incompatible pointer type ‘char (*)[100]’ 
[-Wincompatible-pointer-types]
    3 |   double *p = &x;
      |               ^

这很容易解决,只需更改为

This is very easy to solve by just changing to

double *p = (double*)&x;

我的问题是,演员阵容实际上有什么作用吗?如果不进行强制转换,代码将无效吗?还是仅仅是使编译器安静的一种方法?何时需要铸造?

My question here is, does the casting actually DO anything? Would the code be invalid without the cast? Or is it just a way to make the compiler quiet? When is casting necessary?

我知道您可以对以下代码片段产生一些影响:

I know that you can have some effect with snippets like this:

int x = 666;
int y = (char)x;

但是这不一样吗?

int x = 666;
char c = x;
int y = c;

如果相同,则强制转换为 ,但这不是必需的.对吧?

If it is the same, then the casting does something, but it's not necessary. Right?

请帮助我理解这一点.

推荐答案

铸造可以做几个不同的事情.正如其他答案所提到的,它几乎总是会更改要转换的值的类型(或者可能是该类型的属性,例如 const ).它还可能以某种方式更改数值.但是有很多可能的解释:

Casting can do several different things. As other answers have mentioned, it almost always changes the type of the value being cast (or, perhaps, an attribute of the type, such as const). It may also change the numeric value in some way. But there are many possible interpretations:

    有时,它只是使警告静音,不执行任何真实"操作.根本没有转换(就像许多指针强制转换一样).
  • 有时它会静默警告,只保留类型更改,而不保留值更改(就像其他指针强制转换一样).
  • 有时候,类型更改尽管不涉及明显的值更改,但暗示非常语义不同,以便以后使用该值(同样,在许多指针转换中也是如此).
  • 有时它要求进行一次毫无意义或不可能的转换.
  • 有时它执行的转换是编译器自己执行的(带有或不带有警告).
  • 但是有时它会强制执行编译器无法执行的转换.
  • Sometimes it merely silences a warning, performing no "real" conversion at all (as in many pointer casts).
  • Sometimes it silences a warning, leaving only a type change but no value change (as in other pointer casts).
  • Sometimes the type change, although it involves no obvious value change, implies very different semantics for use of the value later (again, as in many pointer casts).
  • Sometimes it requests a conversion which is meaningless or impossible.
  • Sometimes it performs a conversion that the compiler would have performed by itself (with or without a warning).
  • But sometimes it forces a conversion that the compiler wouldn't have performed.

此外,有时编译器尝试发出的警告,强制转换静音,无害和/或令人讨厌的提示,但有时它们是真实的,并且代码很可能会失败(即,如静音警告试图告诉您).

Also, sometimes those warnings that the compiler tried to make, that a cast silences, are innocuous and/or a nuisance, but sometimes they're quite real, and the code is likely to fail (that is, as the silenced warning was trying to tell you).

对于一些更具体的示例:

For some more specific examples:

更改类型但不更改值的指针强制转换:

A pointer cast that changes the type, but not the value:

char *p1 = ... ;
const char *p2 = (const char *)p;

另一个:

unsigned char *p3 = (unsigned char *)p;

以更显着的方式更改类型的指针强制转换,但这可以保证(在某些体系结构上,它也可能会更改值):

A pointer cast that changes the type in a more significant way, but that's guaranteed to be okay (on some architectures this might also change the value):

int i;
int *ip = &i;
char *p = (char *)ip;

同样重要的指针强制转换,但很可能 还行:

A similarly significant pointer cast, but one that's quite likely to be not okay:

char c;
char *cp = &c;
int *ip = (int *)cp;
*ip = 5;                  /* likely to fail */

毫无意义的指针强制转换,即使使用显式强制转换,编译器也拒绝执行它:

A pointer cast that's so meaningless that the compiler refuses to perform it, even with an explicit cast:

float f = 3.14;
char *p = (char)f;        /* guaranteed to fail */

进行转换的指针强制转换,但无论如何编译器都将进行转换:

A pointer cast that makes a conversion, but one that the compiler would have made anyway:

int *p = (int *)malloc(sizeof(int));

(这是一个坏主意,因为在您忘记包含< stdlib.h> 来声明 malloc()的情况下,强制类型转换可以静默警告,可能会警告您该问题.)

(This one is considered a bad idea, because in the case where you forget to include <stdlib.h> to declare malloc(), the cast can silence a warning that might alert you to the problem.)

由于C语言中非常的特殊情况,从整数到指针的三个强制转换实际上是定义明确的:

Three casts from an integer to a pointer, that are actually well-defined, due to a very specific special case in the C language:

void *p1 = (void *)0;
char *p2 = (void *)0;
int *p3 = (int *)0;

从整数到指针的两次强制转换不一定有效,尽管编译器通常会做明显的事情,而强制转换将使否则的警告消失:

Two casts from integer to pointer that are not necessarily valid, although the compiler will generally do something obvious, and the cast will silence the otherwise warning:

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 非常可疑的转换:

A very questionable cast from a pointer back to an int:

char *p = ... ;
int i = (int)p;

从指针到整数应该足够大的强制转换:

A less-questionable cast from a pointer back to an integer that ought to be big enough:

char *p = ... ;
uintptr_t i = (uintptr_t)p;

改变类型但扔掉"演员表.而不是转换"值,并且使警告消失:

A cast that changes the type, but "throws away" rather than "converting" a value, and that silences a warning:

(void)5;

一种进行数字转换的转换,但无论如何编译器都可以进行转换:

A cast that makes a numeric conversion, but one that the compiler would have made anyway:

float f = (float)0;

一种可更改类型和解释值的强制转换,尽管通常不会更改位模式:

A cast that changes the type and the interpreted value, although it typically won't change the bit pattern:

short int si = -32760;
unsigned short us = (unsigned short)si;

进行数字转换的强制转换,但是编译器可能会警告过的强制转换:

A cast that makes a numeric conversion, but one that the compiler probably would have warned about:

int i = (int)1.5;

进行转换的编译器将进行转换:

A cast that makes a conversion that the compiler would not have made:

double third = (double)1 / 3;

最重要的是,演员绝对可以做事:其中一些有用,其中一些不必要但无害,其中一些很危险.

The bottom line is that casts definitely do things: some of them useful, some of them unnecessary but innocuous, some of them dangerous.

这些天来,许多C程序员之间的共识是,大多数强制转换是或应该是不必要的,这意味着避免显式强制转换是一个不错的规则,除非您确定知道自己在做什么,并且合理地做到这一点.怀疑您在别人的代码中发现的显式强制转换,因为它们很可能是麻烦的征兆.

These days, the consensus among many C programmers is that most casts are or should be unnecessary, meaning that it's a decent rule to avoid explicit casts unless you're sure you know what you're doing, and it's reasonable to be suspicious of explicit casts you find in someone else's code, since they're likely to be a sign of trouble.

最后一个例子是,在过去,确实使灯泡在指针投射方面对我来说一直亮着:

As one final example, this was the case that, back in the day, really made the light bulb go on for me with respect to pointer casts:

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.(有问题的代码是一个动态链接器,执行符号重定位.)

Those three instances of loc += val do three pretty different things: one updates a byte, one updates a 16-bit int, and one updates a 32-bit int. (The code in question was a dynamic linker, performing symbol relocation.)

这篇关于铸造实际上有什么作用吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆