【问题标题】:Unsigned char automatically promoted to int in function call, why?unsigned char 在函数调用中自动提升为int,为什么?
【发布时间】:2013-02-07 07:26:48
【问题描述】:

为什么在调用函数时unsigned char 会自动提升为int?在下面的示例中,有一个 f(int) 和一个 f(char) 函数。编译器将unsigned char 参数强制为char 并调用f(char) 似乎更合乎逻辑,因为它们具有相同的位数。它改为调用f(int),即使这意味着将参数提升为具有更多位的类型。任何指向规则定义位置的指针?标准还是编译器/平台特定?

#include <iostream>

void f( int key )
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

void f( char key )
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

int main( int argc, char* argv[] )
{
    int a = 'a';
    char b = 'b';
    unsigned char c = 'c';

    f(a);
    f(b);
    f(c);

    return 0;
}

产生这个输出:

void f(int)
void f(char)
void f(int)

【问题讨论】:

  • unsigned char 的所有可能值都可以用int 表示。它们不能全部由签名的char 表示。

标签: c++


【解决方案1】:

因为unsigned char 不能用char 表示。例如,如果它们都是 8 位,并且您的 unsigned char 包含值 255,则会溢出 signed char - 并且有符号整数溢出会调用未定义的行为。无论如何,可打印字符通常预计存储在char 而不是unsigned char (C 字符串的类型是char[] 而不是unsigned char[] 等)

所以提升到int 是表示大于1 &lt;&lt; (CHAR_BIT - 1) 的值的必要条件。

【讨论】:

  • 但请注意下面 M3taSpl0it 的回答:char 是有符号还是无符号是由实现决定的,因此理论上,此代码的行为会因编译器而异。
  • @JackAidley 是的,它会,但是在这个特定的例子中(以及在大多数实现中)它是签名的。
  • 确实,但总的来说还是值得注意的
【解决方案2】:

我相信该标准的正确派生基于以下段落,该段落位于第 13.3.3 节 最佳可行函数,即它是函数重载解析(非常复杂)规则的一部分.

(§13.3.3.2/4) 标准转换序列按其等级排序:完全匹配是比提升更好的转换,它是比转换更好的转换。除非以下规则之一适用,否则具有相同等级的两个转换序列是无法区分的:[...]

unsigned char 转换为int 被归类为促销(在§4.5 中定义;阅读以下内容时,请注意(unsigned) char 是一个整数类型) :

§4.5 整体促销
[...]

(§4.5/2) 整数转换等级 (4.13) 小于 int 等级的除 bool、char16_t、char32_t 或 wchar_t 以外的整数类型的纯右值可以转换为 int 类型的纯右值 if int可以表示源类型的所有值;否则,源纯右值可以转换为 unsigned int 类型的纯右值。

而将unsigned char 转换为char 不属于促销,因为它们的等级相同:

(§4.13/1) [...] char 的等级应等于signed char 和unsigned char 的等级。 [...]

它被归类为整体转换(第 4.7 节),并且如上所述,在重载解决期间,提升优于转换。

【讨论】:

    【解决方案3】:

    在 C++ 标准中,char 未定义为无符号或有符号(尽管大小为 1 字节),因此它是定义的实现。所以在你的实现中,我相信它是签名的字符,这就是它被提升的原因。

    【讨论】:

      【解决方案4】:

      int 和 char 在 C 和 C++ 中的范围不同,如果是 char,它的范围是 0 到 255,如果是 int,它的范围是 65535(int 的范围会因操作系统而异)。所以编译器只是把它当作 int 对待。

      【讨论】:

      • char (signed) 实际上的取值范围是-128 到 127 和 unsigned char 不同,取值范围是 0 到 255。
      • 那么当作为参数传递时,编译器区分有符号和无符号?
      • 请参阅here 以获取示例。它基于 ARM,但许多平台应该面临同样的问题。一般来说,混合它们并不是一个好主意。
      猜你喜欢
      • 2013-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多