【问题标题】:Is char default-promoted?char 是默认提升的吗?
【发布时间】:2012-08-16 11:02:37
【问题描述】:

这可能是一个愚蠢的问题,但有人可以提供 C++11 和 C11 的标准参考:

char 是否默认提升为 int

这里有一点背景:C 和 C++ 都有默认参数提升的概念(C++11:5.2.2/7;C11:6.5.2.2/6)。这意味着在以下调用中,参数被提升:

void f(int, ...);

float a = 1; short int b = 2; char c = 'x';

f(0, a, b, c);

对于函数调用,a 转换为 doubleb 转换为 int。但是c 会发生什么?一直觉得char也升为int,但是在标准里找不到相关的说法。

【问题讨论】:

  • 您可以使用sizeof 进行检查,如果它是 int,您将得到 4,如果它是 char,您将得到 1。
  • @elyashiv - 这里的一个问题是函数调用和sizeof 的提升规则不同。而 sizeof('x') 在 C 和 C++ 中是不同的。
  • 这些规则也带来了一些乐趣,如“std::cout
  • @BoPersson:另外,'x'type 在 C 和 C++ 中是不同的! :-)
  • 在 C 中,值 'x' 的类型为 int。该值被转换为类型 char 用于分配。

标签: c++ c language-lawyer integer-promotion


【解决方案1】:

首先,默认参数提升

6.5.2.2

如果表示被调用函数的表达式有 不包含原型的类型,整数提升 对每个参数执行,以及具有浮点类型的参数 被提升为双倍。这些被称为 default 参数 促销

现在进行整数促销:

6.3.1.1

以下内容可以用在表达式中,只要是 int 或 unsigned 可以使用 int:

  • 具有整数类型的对象或表达式(除了 int 或 unsigned int) 其整数转换等级小于或 等于 int 和 unsigned int 的秩。

如果一个 int 可以表示原始类型的所有值(受限制 通过宽度,对于一个位域),该值被转换为一个 int; 否则,它将转换为无符号整数。这些被称为 整数促销

所以对于 C,至少 char 被默认提升为 intunsigned int

【讨论】:

  • 你确定“任何地方都可以使用int或unsigned int”是指“没有原型”或“省略号”的情况吗?那句话让我很困惑。
  • @KerrekSB 我没有看到任何歧义。 “任何地方”似乎包罗万象,因此必须特别提及不同的行为。
  • 好的,但是省略号是否意味着“可以使用 int 或 unsigned int”?我不确定接下来会发生什么。
  • "所以对于 C,至少一个 char 被默认提升为 int。" -- 或unsigned int,在那些char 未签名且CHAR_MAX 不能表示为int 的罕见系统上。
  • @KerrekSB 好吧,我怀疑我们是否会在标准中找到它,我一直认为这是理所当然的。
【解决方案2】:

C++

在 C++ 2011 (ISO/IEC 14882:2011) 中,相关部分似乎是:

§5.2.2 函数调用[expr.call]

¶6 一个函数可以被声明为接受更少的参数(通过声明默认参数(8.3.6))或更多 参数(通过使用省略号、... 或函数参数包 (8.3.5))比参数的数量 在函数定义(8.4)中。 [注意:这意味着,除了省略号 (...) 或函数 使用参数包,每个参数都有一个参数。 ——尾注]

¶7 当给定参数没有参数时,参数的传递方式使得接收方 函数可以通过调用 va_arg (18.10) 来获取参数的值。 [注:本段不 适用于传递给函数参数包的参数。函数参数包在 模板实例化(14.5.3),因此每个这样的参数在函数时都有一个对应的参数 实际上调用了模板特化。 —尾注] 左值到右值 (4.1)、数组到指针 (4.2) 和 函数到指针 (4.3) 标准转换是在参数表达式上执行的。一个论点 具有(可能是 cv 限定的)类型 std::nullptr_t 被转换为类型 void* (4.10)。在这些转换之后, 如果参数没有算术、枚举、指针、指向成员的指针或类类型,则 程序格式不正确。传递具有非平凡的类类型(第 9 条)的潜在评估参数 复制构造函数、非平凡的移动构造函数或非平凡的析构函数,没有对应的 参数,有条件地支持实现定义的语义。

如果参数有整数 或受积分提升 (4.5) 约束的枚举类型,或受约束的浮点类型 到浮点提升(4.6),参数的值被转换为提升类型之前 通话。这些提升称为默认参数提升。

我将最后两个句子分开以强调它们。它们是标准第 7 段的连续部分。

§4.5 整体促销 [conv.prom]

¶1 整数类型的纯右值,而不是 boolchar16_tchar32_twchar_t,其整数转换 rank (4.13) 小于int 的rank 可以转换为int 类型的prvalue 如果int 可以代表所有 源类型的值;否则,源纯右值可以转换为unsigned int 类型的纯右值。

¶2 char16_tchar32_twchar_t (3.9.1) 类型的纯右值可以转换为第一个纯右值 以下类型可以表示其基础类型的所有值:intunsigned intlong intunsigned long intlong long intunsigned long long int。如果该列表中的任何类型都不能 表示其底层类型的所有值,char16_tchar32_twchar_t 类型的纯右值可以是 转换为其基础类型的纯右值。

等等


C

C 有两个默认提升参数的上下文。一种是函数范围内没有原型(首先由另一个答案覆盖),第二种是有省略号的原型。当然,C++ 根本不允许第一种情况。这些引用来自另一个答案选择的标准的相同部分,但这里的 sn-ps 有点长。它们是通过独立分析标准发现的,只是在交叉检查时才发现这些部分是相同的。

在 C 2011 (ISO/IEC 9899:2011) 中,相关部分似乎是:

§6.5.2.2 函数调用

¶6 如果表示被调用函数的表达式的类型不包含 原型,整数提升对每个参数执行,参数 具有 float 类型的提升为 double。这些被称为默认参数 促销。如果参数的数量不等于参数的数量,则 行为未定义。如果函数是使用包含原型的类型定义的,并且 原型以省略号 (, ...) 或后面的参数类型结尾 提升与参数的类型不兼容,行为未定义。 如果函数是用不包含原型的类型定义的,那么 提升后的参数与之后的参数不兼容 促销,行为未定义,但以下情况除外:

——一个提升类型是有符号整数类型,另一个提升类型是 对应的无符号整数类型,并且值在两种类型中都可以表示;

——这两种类型都是指向字符类型的合格或不合格版本的指针,或者 无效。

¶7 如果表示被调用函数的表达式具有包含原型的类型, 参数被隐式转换,就像通过赋值一样,转换为 对应的参数,取每个参数的类型为不合格版本 其声明的类型。函数原型声明器中的省略号表示 参数类型转换在最后一个声明的参数之后停止。默认参数 提升是在尾随参数上执行的。

“整数促销”在 §6.3.1.1 中定义:

§6.3.1 算术操作数

§6.3.1.1 布尔值、字符和整数

¶1 每个整数类型都有一个整数转换等级,定义如下:

——没有两个有符号整数类型具有相同的等级,即使它们具有相同的等级 表示。

——有符号整数类型的秩应大于任何有符号整数的秩 输入精度较低。

——long long int 的秩应大于 long int 的秩,即 应该大于int的rank,int的rank应该大于short的rank int,应大于signed char的等级。

——任何无符号整数类型的等级应等于相应的等级 有符号整数类型,如果有的话。

——任何标准整数类型的秩应大于任何扩展的秩 等宽的整数类型。

——char的秩应该等于signed char和unsigned char的秩。

——_Bool 的等级应小于所有其他标准整数类型的等级。

——任何枚举类型的秩应等于兼容整数类型的秩 (见 6.7.2.2)。

——任何扩展有符号整数类型相对于另一个扩展有符号整数类型的等级 具有相同精度的整数类型是实现定义的,但仍受制于 确定整数转换等级的其他规则。

- 对于所有整数类型 T1、T2 和 T3,如果 T1 的秩大于 T2 且 T2 具有 排名大于 T3,则 T1 排名大于 T3。

¶2 以下内容可用于intunsigned int 可能出现的表达式中 使用:

- 具有整数类型的对象或表达式(intunsigned int 除外) 其整数转换等级小于或等于int 的等级并且 unsigned int.

——_Boolintsigned intunsigned int 类型的位字段。

如果int 可以表示原始类型的所有值(受宽度限制,对于 位域),该值被转换为int;否则,它将转换为unsigned int。这些被称为整数提升58) 整数促销。

58) 整数提升仅适用于:作为通常算术转换的一部分,对某些 参数表达式,一元 +、- 和 ~ 运算符的操作数,以及 移位运算符,由它们各自的子条款指定。


我注意到有一次,问题列出了函数void f(...);,这是一个C++函数而不是C函数; C 不允许省略号作为函数的唯一参数出现。该问题已更新为void f(int, ...);,在 C 和 C++ 中均有效。

【讨论】:

  • 哦,不用考虑省略号,我可以添加一个引导参数。我忘记了这种区别(不过,这很好!)。
  • 太棒了!我一定对 4.5 的存在视而不见 :-(
猜你喜欢
  • 1970-01-01
  • 2015-02-20
  • 1970-01-01
  • 1970-01-01
  • 2013-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-25
相关资源
最近更新 更多