当我在C ++中时,我调用了一个重载函数foo,如下所示:
foo('e' - (char) 5)
它可以输出"这是一个字符#34;或者"这是一个int"根据类型结果。我得到了#34;这是一个int"从我的程序,像这样:
#include <iostream>
void foo(char x)
{
std::cout << "output is a char" << std::endl;
}
void foo(int x)
{
std::cout << "output is an int" << std::endl;
}
int main()
{
foo('a' + (char) 5);
}
我的导师说在C中,上面的表达式('a' + (char) 5)
计算为char。我在C99标准中看到,字符被提升为整数以查找总和,但是当它完成时C是否会将它们重新转换为字符?我无法找到任何看似可信的参考文献,说明促销完成后C实际做了什么,并找到了总和。
总和是作为int保留还是作为char给出?我如何在C中证明这一点,或者是否有我不理解/发现的参考?
答案 0 :(得分:6)
从C标准,6.3.1.8通常的算术转换,强调我的:
许多期望算术类型操作数的运算符会导致转换并产生结果 以类似的方式输入类型。目的是确定操作数的通用实数类型 和结果。对于指定的操作数,将转换每个操作数,而不更改类型 域,对应的实类型是常见的实类型。的除非 另外明确说明,常见的真实类型也是相应的实际类型 结果,其类型域是操作数的类型域,如果它们相同, 否则复杂。此模式称为通常的算术转换:
- 首先,如果任一操作数的相对实数类型为
long double
...- 否则,如果任一操作数的相应实数类型为
double
...- 否则,如果任一操作数的相应实数类型为
float
...- 否则,对两个操作数执行整数提升。然后将以下规则应用于提升的操作数:
- 如果两个操作数具有相同的类型,则不需要进一步转换。
所以你完全正确。表达式'a' + (char) 5
的类型为int
。除非用户明确要求,否则不会重新发送回char
。请注意,'a'
此处的类型为int
,因此它只是需要提升的(char)5
。这在6.4.4.4字符常量中规定:
整数字符常量是包含的一个或多个多字节字符的序列 在单引号中,如
'x'
...
整数字符常量的类型为int
。
有一个例子证明明确重铸为char
:
执行片段
char c1, c2; /* ... */ c1 = c1 + c2
'整数促销''要求抽象机器将每个变量的值提升为
int
大小,然后添加两个int
并截断总和。如果可以在没有溢出的情况下添加两个char
,或者以静默方式溢出包装以产生正确的结果,则实际执行只需要产生相同的结果,可能省略促销。
此处的截断只会发生,因为我们会分配回char
。
答案 1 :(得分:3)
不,C不会将它们重新制作回字符。
标准(ISO / IEC 9899:1999)说(6.3.1.8常规算术转换):
许多期望算术类型操作数的运算符会导致转换并产生结果 以类似的方式输入类型。目的是确定操作数的通用实数类型 和结果。对于指定的操作数,将转换每个操作数,而不更改类型 域,对应的实类型是常见的实类型。的除非强> 另有明确说明,常见的实际类型也是相应的实际类型 结果,其类型域由运营商确定。
答案 2 :(得分:2)
你的导师似乎错了。除了你的标准发现算术提升到int
之外,我们可以使用一个简单的测试程序来显示行为(当然没有标准证明,但与C ++测试的证明水平相同):
#include <stdio.h>
int main () {
printf("%g",'c' - (char)5);
}
生成
警告:format指定类型'double'但参数的类型为'int'
答案 3 :(得分:0)
它被提升为int
,没有什么可以告诉编译器它应该使用其他任何东西。你可以转换回这样的字符:
foo((char)('a' + 5));
这告诉编译器将计算结果视为char
,否则将其保留为int
。
答案 4 :(得分:0)
来自C ++标准(C ++ Working Draft N3797,5.7 Additive operators)
1添加剂操作符+和 - 从左到右组。 通常 对算术或算术的操作数执行算术转换 枚举类型。
和(5个表达式)
10许多期望算术或算术操作数的二元运算符 枚举类型导致转换并产生类似的结果类型 办法。目的是产生一种普通类型,它也是一种类型 结果。这种模式称为通常的算术转换, 其定义如下:
...
- 否则,应执行整体促销(4.5) 两个操作数 .62然后以下规则应适用于 推广操作数:
因此函数调用中的表达式
foo('a' + (char) 5);
的类型为int
。
要使用char类型的参数调用重载函数,您必须编写例如
foo( char( 'a' + 5 ) );
或
foo( ( char )( 'a' + 5 ) );
或者您可以像
一样使用C ++强制转换foo( static_cast<char>( 'a' + 5 ) );
C ++标准的上述引用也适用于C标准。可见的区别在于,在C ++中,字符文字的类型为char
,而在C中,它们的类型为int
。
所以在C ++中声明的输出
std::cout << sizeof( 'a' ) << std::endl;
将等于1.
在C语句中输出语句
printf( "%zu\n", sizeof( 'a' ) );
将等于sizeof( int )
,通常等于4。
答案 5 :(得分:0)
第6.5.2.2/6节
如果表示被调用函数的表达式具有类型 不包括原型,执行整数促销 每个论点......
所以问题的答案取决于函数原型。如果函数声明为
void foo(int x)
或
void foo()
然后函数参数将作为int
传递。
OTOH,如果函数声明为
void foo( char x )
然后表达式的结果将隐式转换为char
。
答案 6 :(得分:0)
在C中(与C ++不同),字符文字'a'
的类型为int
(§6.4.4.4¶10:“整数字符常量的类型为int
。”)
即使不是这种情况,C标准也明确规定在评估运算符+
之前,“[i]两个操作数都有算术类型,对它们执行通常的算术转换。 “ (C11,§6.5.6¶4)在这方面,C和C ++具有相同的语义。 (参见C ++的[expr.add]
§5.7¶1)