【问题标题】:When are explicit casts actually needed?什么时候真正需要显式强制转换?
【发布时间】:2020-10-10 02:29:28
【问题描述】:

以这段代码为例:

const char *s;
char *t = s;

这会发出这个:warning: assignment discards 'const' qualifier from pointer target type

只需添加一个强制转换,就可以很容易地使编译器静音:

char *t = (char*)s;

你可以对常规变量做类似的事情,而不仅仅是指针,它不仅适用于 const 限定符。您基本上可以从任何类型转换为任何类型,即使其中一些转换会造成麻烦。

我还读到你永远不应该转换 malloc,因为 void 指针的转换总是安全的。

但铸造实际上做了什么?除了阻止编译器发出警告之外,它是否还有其他作用。什么时候真正需要显式强制转换?

澄清:

我在这里谈论作业。不是double res = (double)a / b 之类的东西。在那种情况下,我知道强制转换的作用,在这种情况下,我们可以轻松地摆脱显式强制转换,转而使用如下的隐式强制转换:double c = a; double res = c/b; 或只是 double res = (1.0 * a) / b

【问题讨论】:

  • 我不确定是否存在不能使用变量的情况,但它通常会降低 (double)a / b 等表达式的可读性以避免整数除法。你问的是这个吗?
  • @Ry- 我会澄清的。一秒。
  • 另外,这些警告似乎是关于不符合标准的代码,并且允许是错误:stackoverflow.com/questions/36828742/…
  • 底线是演员通过告诉编译器schar* 类型而不是const char* 来掩盖警告,因此它允许在没有警告的情况下分配给t -- 但是 -- (总是有一个但是...)现在t 指向s,但是...t 是可变的,任何接收t 的函数都可以有效地假设它指向可变内存——这是不是这种情况,如果有东西试图修改t 指向的内存(它恰好是字符串文字等)——BAM SEGFAULT。本质上,强制转换使编译器对t 的类型成为谎言。
  • 这是一个有趣的问题。有一些转换实际上改变了编译器生成的代码,比如(double)a/b 变体,还有一些只允许编译器接受它会抱怨的代码。我不确定“在哪里需要显式转换”的问题是否有一句话的答案。

标签: c casting


【解决方案1】:

C 2018 6.5.16.1 1 指定了简单赋值运算符的约束。对于除了指向void 的指针之外的指针的左右操作数,这些表示:

应满足以下条件之一: ... 两个操作数都是指向兼容类型的合格或非合格版本的指针,左侧指向的类型具有右侧指向的类型的所有限定符; …

因此,C 标准要求指针具有相同的“种类”(兼容类型),并且赋值不能删除任何限定符(左侧具有右侧的所有限定符,但可能更多)。如果违反此要求,编译器必须发出诊断消息(尽管它仍然可以选择接受程序;该消息可以是警告而不是错误)。

6.5.4 在第 2 到第 4 段中指定了强制转换的约束。它们都没有限制从一种指针类型到另一种指针类型的转换。因此,您可以使用强制转换指定任何指针转换,并且编译器不需要发出诊断(尽管有些人可能会选择)。

其基本原理是,赋值允许您隐式地执行“正常”使用指针的转换,但显式使用强制转换允许“特殊”使用指针。

允许使用强制转换进行特定转换这一事实并不一定意味着它是有意义的或定义明确的。 6.3.2.3 定义了一些指针转换的规则。例如,int * 可以转换为char *,生成的指针可用于检查表示int 的字节。但是将char * 转换为int * 可能会导致未定义的行为。因此,强制转换将允许您进行转换,但结果是否有用还是您想要的结果取决于 C 标准中的其他规则。

当允许并定义转换时,无论它是通过赋值隐式发生还是通过强制转换显式发生,都会产生相同的效果。演员表不会改变转换是什么;它只会改变是否允许(没有诊断)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-13
    • 1970-01-01
    • 1970-01-01
    • 2016-07-27
    • 2010-12-13
    相关资源
    最近更新 更多