c - 类型转换实际上有什么作用吗?

标签 c casting

考虑以下代码段:

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/

    相关文章:

    actionscript-3 - ActionScript 3 : Why would you omit the new keyword when instantiating a custom eventDispatcher?

    java - 从父类(super class)构造子类

    mysql - 错误 1690 (22003) : BIGINT UNSIGNED value is out of range in

    sql - 在 Informix 中将整数转换为 bool 值

    c - 编译程序时cs50的IDE出现问题

    c - 尝试递增字母时出现段错误

    c - 线程函数 sum_array() 无法被 main 函数调用

    c - 为什么我的 c 函数 translate() 返回随机符号?

    C指针混淆——指向char数组的指针

    postgresql - 将 varchar 字段的类型更改为整数 : "cannot be cast automatically to type integer"