【问题标题】:Why can I implicitly convert an int literal to an int * in C but not in C++?为什么我可以在 C 中将 int 文字隐式转换为 int * 而在 C++ 中却不能?
【发布时间】:2012-01-07 11:29:28
【问题描述】:

我相信在下面的代码中,C“自动将 17 转换为 int *”,正如最近有人指出的那样(但没有给出原因),这是错误的。

int *ptoi = 17; // I assumed that 17 is being automatically casted to int *

我知道,如果我在 C++ 中执行与上述相同的操作,我会收到错误消息 invalid conversion from int to int *。但是如果我在 C++ 中执行以下操作,它就可以正常工作:

int *ptoi = (int *)17;

这就是我认为在 C 中强制转换是隐式的原因。

有人能解释一下为什么在 C++ 中我必须强制转换它,但在 C 中它可以正常工作吗?

【问题讨论】:

  • +1 表示合法使用 C 和 C++ 标签的问题 ;-)
  • 我猜 C++ 会进行更严格的类型检查。 C 中的强制转换不应该给你一个指向“17”的指针。它是一个值为“17”的指针(指向“内存地址”17)。作为一种解决方法,我认为您始终可以转换为 void*,然后转换为其他指针类型。
  • C 和 C++ 是不同的语言。 C++ 在很多方面都比 C 更严格,其中之一就是从一种类型到另一种类型的隐式转换。

标签: c++ c pointers casting


【解决方案1】:

在 C 中从整数到不进行强制类型转换的指针的转换也是非法的。但大多数编译器都会让你侥幸逃脱。 Clang 给出警告:

example.c:5:8: warning: incompatible integer to pointer conversion initializing
      'int *' with an expression of type 'int'
  int *x = 17;
       ^   ~~

C99 在第 6.5.4 节强制转换运算符第 4 段中说:

涉及指针的转换,除了 6.5.16.1 的约束允许的情况外,应通过显式强制转换来指定。

6.5.16.1 是 void * 转换为其他指针而不需要强制转换的例外。

C++ 规范在第 5.4 节显式类型转换(强制转换表示法),第 3 段中说:

以下未提及且未由用户明确定义的任何类型转换都是格式错误的。

所以你去 - 这两种语言都是非法的,但为了与许多旧软件兼容,很多 C 编译器会让你侥幸逃脱。

【讨论】:

  • “在 C 中从整数到没有强制类型转换的指针的转换也是非法的。”不根据 6.3.2.3/5:“整数可以转换为任何指针类型。除非前面指定,结果是实现定义的,可能未正确对齐,可能不指向引用类型的实体,并且可能是一个陷阱表示。56)" 简而言之,结果可能没有意义,但肯定不是非法
  • @JohnBode,要合法,它需要明确的演员表,如我上面的引文中所述。这样做当然是合法的int *x = (int *)17
  • @JohnBode 6.3.2.3(5) 正在谈论转换的结果,但这不是这里的问题。 6.5.16.1(1) 讨论了在赋值操作中允许哪些隐式转换。唯一允许左操作数为指针类型而右操作数为整数的情况是 case 5,限制是右操作数是空指针常量,而 17 不是。 6.5.4(3) 说“涉及指针的转换,除了 6.5.16.1 的约束允许的情况外,应通过强制转换指定。”
  • @Raymond - 是的,在阅读 6.5.16.1(1) 之后,我意识到你不能在没有强制转换的情况下将整数分配给指针。
  • @mtahmed “现在我要把这个答案放在那个人的脸上!” ——完全错误的推论。 'C "自动将 17 转换为 int *"' 确实是错误的。
【解决方案2】:

是的,转换在 C 中是隐式的,尽管许多(全部?)编译器都会发出警告。在 C++ 中,不会执行从 intint* 的隐式转换,因此需要显式转换。

【讨论】:

    【解决方案3】:

    C 具有隐式转换——根据我的经验,几乎可以从任何整数类型转换为任何其他整数类型。 C 中的指针是被认为是整数scalar 类型。

    在 C++ 中,整型定义如下:

    boolcharchar16_tchar32_twchar_t 类型以及 signedunsigned 整数类型统称为 称为整数类型。48 整数类型的同义词是整数类型。整数类型的表示 应使用纯二进制计数系统定义值。49 [ 示例:本国际标准 允许整数类型的 2 的补码、1 的补码和有符号幅度表示。 -结尾 例子]

    在 C++ 中唯一可以转换为指针类型的整数值是 空指针常量,尽管从技术上讲,转换是转换为 std::nullptr_t 类型的 prvalue。 (第 4.10 段)

    最后说明

    而不是像这样修复它:

    int *ptoi = (int *)17;
    

    考虑添加 C++ 风格的演员表:

    int *ptoi = reinterpret_cast<int*>(17);
    

    明确您尝试调用的转换类型

    【讨论】:

    • 就我个人而言,我从未见过reinterpret_cast&lt;int*&gt; 优于(int*)。只是更多的打字。
    • 指针不是 C99 中的整数类型。整数是算术类型,算术和指针类型都是标量类型,但这不是一回事。
    • @CarlNorum:谢谢卡尔,我没有 C99 标准 hndy 的副本;会修改我的帖子。
    • 在这种情况下确实没有任何歧义。如果搜索重新解释演员表非常重要,您可以添加 // reinterpretion cast 评论。这并不是说 C++ 风格的强制转换不是一件好事——肯定有重要的用例。
    • “所以现在你提议添加评论”——不,我的意思是可搜索性是添加语言功能的糟糕基础; reinterpret_cast 应该取决于它的语义。我是说没有真正需要搜索将整数分配给指针变量的实例......这是一个临时的理由。
    【解决方案4】:

    编译器会将int *ptoi = 17; 解释为指向位置17 (0x00000011) 处的整数的变量ptoi。

    C 只是一种完全不同的语言。它可能看起来像 C++,但事实并非如此。两种语言适用不同的规则。

    我可能应该指出,C 和 C++ 都会(据我所知)将其设为指向 0x00000011 的指针,但 C 的抱怨较少,因为分配内存位置在 C 中并非无效。

    【讨论】:

    • 不太正确:编译器会将int *ptoi = 17; 解释为一个变量ptoi,它指向 存储在内存位置17 中的一个整数。
    • 呃,当我把它们写在 SO 上时,我总是把它们弄糊涂。固定!
    • 'C 只是一种完全不同的语言'——这是夸大其词。请参阅 Bjarne Stroustrup 的www2.research.att.com/~bs/bs_faq.html#C-is-subset
    • '因为分配内存位置在 C 中不是无效的'——它在 C++ 中或多或少是无效的;后者只需要一个明确的演员表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-07
    • 2017-07-17
    • 1970-01-01
    • 2016-06-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多