C 如何处理 char 和?

How does C treat char sums?

当我在 C++ 中调用重载函数 foo 时,如下所示:

foo('e' - (char) 5)

它可以根据类型结果输出"this is a char"或"this is an int"。我从我的程序中得到 "this is an 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) 的计算结果是一个字符。我在 C99 标准中看到 chars 被提升为 ints 以求和,但是 C 是否在完成后将它们重新转换为 chars?我找不到任何看起来可信的参考资料,以某种方式说明 C 在完成提升后实际做了什么,并找到了总和。

总和是作为 int 还是作为 char 给出的?我如何在 C 中证明这一点,或者是否有我不是 understanding/finding?

的参考

你的导师好像错了。除了你的标准发现算术提升到 int,我们可以使用一个简单的测试程序来显示行为(当然没有标准证明,但与你的 C++ 测试相同级别的证明):

#include <stdio.h>

int main () {
   printf("%g",'c' - (char)5);
}

产生

Warning: format specifies type 'double' but argument has type 'int'

gcc and clang.

它被提升为 int,没有什么可以告诉编译器它应该使用其他任何东西。您可以像这样转换回字符:

foo((char)('a' + 5));

这告诉编译器将计算结果视为 char,否则将其保留为 int

不,C 不会将它们重铸回字符。

标准(ISO/IEC 9899:1999)说(6.3.1.8 常用算术转换):

Many operators that expect operands of arithmetic type cause conversions and yield result types in a similar way. The purpose is to determine a common real type for the operands and result. For the specified operands, each operand is converted, without change of type domain, to a type whose corresponding real type is the common real type. Unless explicitly stated otherwise, the common real type is also the corresponding real type of the result, whose type domain is determined by the operator.

来自 C 标准,6.3.1.8 常用算术转换,强调我的:

Many operators that expect operands of arithmetic type cause conversions and yield result types in a similar way. The purpose is to determine a common real type for the operands and result. For the specified operands, each operand is converted, without change of type domain, to a type whose corresponding real type is the common real type. Unless explicitly stated otherwise, the common real type is also the corresponding real type of the result, whose type domain is the type domain of the operands if they are the same, and complex otherwise. This pattern is called the usual arithmetic conversions:

  • First, if the correspeonding real type of either operand is long double...
  • Otherwise, if the corresponding real type of either operand is double...
  • Otherwise, if the corresponding real type of either operand is float...
  • Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:
    • If both operands have the same type, then no further conversion is needed.

所以你是完全正确的。表达式 'a' + (char) 5 的类型是 int。除非用户明确要求,否则不会重铸回 char。请注意,这里的 'a' 具有类型 int,因此只有 (char)5 需要提升。这是6.4.4.4字符常量中规定的:

An integer character constant is a sequence of one or more multibyte characters enclosed in single-quotes, as in 'x'.
...
An integer character constant has type int.

有一个示例演示了显式重铸为 char:

In executing the fragment

char c1, c2;
/* ... */
c1 = c1 + c2

the ‘‘integer promotions’’ require that the abstract machine promote the value of each variable to int size and then add the two ints and truncate the sum. Provided the addition of two chars can be done without overflow, or with overflow wrapping silently to produce the correct result, the actual execution need only produce the same result, possibly omitting the promotions.

这里的截断只是因为我们分配回了 char.

您无法像在 C 中那样轻松地确定表达式的类型,但您可以轻松地确定表达式的大小:

#include <stdio.h>
int main(void) {
    printf("sizeof(char)==1\n");
    printf("sizeof(int)==%u\n", sizeof(int));
    printf("sizeof('a' + (char) 5)==%u\n", sizeof('a' + (char) 5));
    return 0;
}

这给了我:

sizeof(char)==1
sizeof(int)==4
sizeof('a' + (char) 5)==4

这至少证明 'a' + (char) 5 不是 类型 char.

来自 C++ 标准(C++ 工作草案 N3797,5.7 加法运算符)

1 The additive operators + and - group left-to-right. The usual arithmetic conversions are performed for operands of arithmetic or enumeration type.

和(5 个表达式)

10 Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions, which are defined as follows:

...

— Otherwise, the integral promotions (4.5) shall be performed on both operands.62 Then the following rules shall be applied to the promoted operands:

因此函数调用中的表达式

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。

第 6.5.2.2/6 节

If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument...

所以你的问题的答案取决于函数原型。如果函数声明为

void foo(int x)

void foo()

那么函数参数将作为 int 传递。

OTOH,如果函数声明为

void foo( char x )

则表达式的结果将被隐式转换为 char

在 C 中(与 C++ 不同),字符文字 'a' 的类型为 int(§6.4.4.4¶10:"An integer character constant has type int.")

即使情况并非如此,C 标准也明确指出,在计算运算符 + 之前,“[i]如果两个操作数都具有算术类型,则通常的算术转换将在他们。” (C11, §6.5.6 ¶4) 在这方面,C 和 C++ 具有相同的语义。 (参见 C++ 的 [expr.add] §5.7¶1)