2

我几乎假设这是一个愚蠢的问题......但我真的找不到答案。所以我在这里问这个。

为了了解隐式类型转换,我在 C 上运行以下代码。

#include <stdio.h>

int main()
{
    unsigned char i;
    char cnt = -1;

    int a[255];

    for (int k = 0; k < 255; k++)
    {
        a[k] = k;
    }
    for (i = cnt - 2; i < cnt; i--)
    {
        a[i] += a[i + 1];
        printf("%d\n", a[i]);
    }

    return 0;
}

当我运行这个程序时,什么也没发生。

在第一次迭代时,我发现for循环的循环条件为假,所以程序立即退出了for循环。

但是,我不明白为什么。

据我所知,C 在分配或比较不同类型的变量时会进行隐式转换。所以我认为 on i = cnt - 2,减法运算使值 -3,然后隐式转换为 i 分配值 253。

那么,条件不应该i < cnt为真,因为(由于比较有符号和无符号字符而通过另一个隐式转换 cnt)253 小于 255?

如果不是,为什么这是假的?有什么我错过的还是有一些我不知道的例外?

4

2 回答 2

3

你的问题一点也不傻。您接近解决方案:i被赋值,-3但隐式转换为 , 的类型iunsigned char将值更改为253.

为了更准确的解释,您的测试代码中有多个问题:

  • char可能是有符号或无符号的,具体取决于平台和编译器配置,因此char cnt = -1;可以将值-1或存储255到中,或者如果是无符号的并且具有超过 8 位,则cnt甚至可以存储其他值。char

  • 的行为for (i = cnt - 2; i < cnt; i--)还取决于char默认情况下是有符号还是无符号:

    • 在所有情况下,测试i < cnt都是通过将两个操作数转换为int(或unsigned int在极少数情况下为sizeof(int)==1)来评估的。如果可以表示和int类型的所有值,则此转换不会更改值。charunsigned char

    • ifchar是无符号的并且有 8 位,cnt具有值255soi用该值初始化,253循环运行 254 次,i253down 到0,然后i--将值255再次存储到i,测试i < cnt评估为假。循环打印507, then 759, ... 32385

    • ifchar有符号并且有 8 位,就像您的系统上可能的情况一样,cnt具有值-1并使用转换为i的值进行初始化,即. 初始测试评估为,这是错误的,导致立即跳过循环体。-3unsigned char253i < cnt253 < -1

您可以通过为编译器提供适当的标志(例如:)来强制char默认为无符号gcc -funsigned-char并测试行为如何变化。使用Godbolt 的编译器资源管理器,您可以看到gcc仅生成 2 条指令,在有符号(默认)情况下返回 0,在无符号情况下返回预期输出。

于 2021-09-02T13:05:24.137 回答
1

对于初学者,我们假设 typechar表现为 type signed char

在这种情况下

i < cnt

int由于整数提升,两个操作数都被隐式转换为类型。

来自 C 标准(6.5.8 关系运算符)

3 如果两个操作数都具有算术类型,则执行通常的算术转换。

和(6.3.1.8 常用算术转换)

1 许多期望算术类型的操作数的运算符会以类似的方式导致转换和产生结果类型。目的是确定操作数和结果的通用实数类型。对于指定的操作数,每个操作数都在不改变类型域的情况下转换为对应的实数类型是公共实数类型的类型。除非另有明确说明,否则公共实数类型也是结果的对应实数类型,如果它们相同,则其类型域是操作数的类型域,否则为复数。这种模式称为通常的算术转换:

...否则,对两个操作数都执行整数提升。然后将以下规则应用于提升的操作数:

如果两个操作数具有相同的类型,则不需要进一步转换

和(6.3.1.1 布尔值、字符和整数)

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

i因此,在整数促销之后表示的正值0000 0000 1111 1101将大于负值1111 1111 1111 1111

因此 for 循环的条件立即评估为逻辑假,因为类型的正值大于253类型的负值。int-1int

这是一个演示程序。

#include <stdio.h>

int main(void) 
{
    char cnt = -1;
    unsigned char i = cnt - 2;
    
    printf( "cnt = %x\n", ( unsigned int )cnt );
    printf( "i = %x\n", ( unsigned int )i );
    
    printf ( "i < cnt is %s\n", i < cnt ? "true" : "false" );
    
    return 0;
}

程序输出为

cnt = ffffffff
i = fd
i < cnt is false
于 2021-09-02T12:34:41.250 回答