English 中文(简体)
在C89中,从无符号字符转换为有符号字符,反之亦然,这一点是否得到了很好的定义?
原标题:Is converting from unsigned char to signed char and vice versa in C89 well defined?

注意:建议的重复处理的是无符号int有符号int,而不是未符号char有符号char。建议的重复问题处理的是C11。这个问题只涉及C89。这个问题可以重新讨论吗

我的代码:

#include <stdio.h>

int main()
{
    signed char c;
    unsigned char d;

    c = (signed char) -2;
    d = (unsigned char) c;
    printf("%d %d
", c, d);

    d = (unsigned char) 254;
    c = (signed char) d;
    printf("%d %d
", c, d);

    return 0;
}

输出:

$ clang -Wall -Wextra -pedantic -std=c89 foo.c && ./a.out
-2 254
-2 254

对于上述两种转换,在符合标准的C89编译器中,输出是否保证为-2 254?还是输出取决于实现?

最佳回答

在C89中,从无符号字符转换为有符号字符,反之亦然,这一点是否得到了很好的定义?

到<em>unsigned</em>类型的转换定义良好。到签名类型具有实现详细信息。

对于上述两种转换,在符合标准的C89编译器中,输出是否保证为-2 254?

还是输出取决于实现?


并非所有实现都使用8位<code>char</code>,转换为<em>签名的<em>类型会产生实现细节。

规格详细信息:C89转换。此措辞与最近的C规范不同。我没有发现显著差异。


UCHAR_MAX<;=INT_MAX,代码可以在下面使用,并让编译器发出优化的、定义良好的代码。

c = (signed char) (d > SCHAR_MAX ? d - UCHAR_MAX - 1 : d);

可能需要更多的考虑来涵盖所有情况。

问题回答

如果我说错了什么,请纠正我。

您的问题有一个带有“未定义行为”的标志。我认为这是不对的。

如果你对这个程序有任何疑问,我建议你看看这个程序的反汇编代码。你所有的困惑都可以很容易地通过检查来解决。

输出:

-2 254
-2 254

这是正确的,也是中央行为。这种行为是由C语言本身或C语言标准决定的。

输出的关键取决于程序员希望如何解释FE的存储值。如果您将FF视为无符号字符,则它是255(或FFFF作为无符号短字符,它是65535FFFFFFFF4294967295FF视为有符号字符(或FFFF作为有符号短it s-1FFFFFFFF-1),it s-1

正如您将FE视为无符号字符一样,它是254。请将<code>FE</code>作为一个有符号的字符,它是<code>-2

当您要求计算机存储-2254时,计算机不识别正数或负数,它只识别0(在电路中,它可能被称为“断开连接”或“断开”)和1,它将在内存中的某个位置存储FE(因为变量c变量d是char类型,所以它占用1字节)(正如@David c.Rankin所指出的,在用两个互补码编码负符号值的计算机上。

请参阅以下代码:

#include <stdio.h>

int main()
{
    signed char c;
    unsigned char d;

    c = (signed char) 0xFE;
    d = (unsigned char) c;
    printf("%d %d
", c, d);

    d = (unsigned char)0xFE;
    c = (signed char) d;
    printf("%d %d
", c, d);

    return 0;
}

使用以下命令运行它:

clang -Wall -Wextra -pedantic -std=c89 foo.c && ./a.out

将输出:

-2 254
-2 254

为什么输出双-2 254

代码中没有-2254-2254来自哪里?

简单解释:

我们发现变量c可变dchar类型,但%d输出int(或带符号int),编译器现在应该如何进行?答案是有符号扩展和无符号扩展

因此,现在存储在变量c中的值0xFE已通过符号扩展转换为0xFFFFFFFE,存储在变量d的值0xFE已通过零扩展转换为0x000000FE0xFFFFFFFE打印为-2%d时,且0x000000FE254%d。(您是否不太熟悉或不太理解0xFFFFFFFE?下面有解释,让我们继续阅读。)

或者代码如下:

#include <stdio.h>

int main()
{
    signed char c;
    unsigned char d;

    c = (signed char) 254;
    d = (unsigned char) c;
    printf("%d %d
", c, d);

    d = (unsigned char)254;
    c = (signed char) d;
    printf("%d %d
", c, d);

    return 0;
}

使用以下命令运行它:

clang -Wall -Wextra -pedantic -std=c89 foo.c && ./a.out

将输出:

-2 254
-2 254

为了更好地解释您的困惑,请查看以下代码。

#include <stdio.h>

int main()
{
    signed char c;
    unsigned char d;

    c = (signed char) -2;
    d = (unsigned char) c;
    printf("%d %d %u %u
", c, d, c, d);

    d = (unsigned char) 254;
    c = (signed char) d;
    printf("%d %d %u %u
", c, d, c, d);

    return 0;
}

使用以下命令运行它:

clang -Wall -Wextra -pedantic -std=c89 foo.c && ./a.out

将输出:

-2 254 4294967294 254
-2 254 4294967294 254

或者使用以下命令运行它:

gcc -g -o foo foo.c && ./foo

将输出:

-2 254 4294967294 254
-2 254 4294967294 254

输出是正确的。

更多详细说明:

我们发现c或d是char类型,但%u是输出unsignedint,编译器现在应该如何进行?答案是有符号扩展和无符号扩展

当我们检查反汇编代码时,我们确实发现了符号扩展和零扩展。见下图:

我们发现,当为变量c变数d赋值时使用字符类型(BYTE),但在之前打印可变c可变d的值时,有一些指令,如movzx esi、BYTE PTR[rbp-0x1]movsx ecx、BYTE PTR[rbp-0x2]vsx-eax,字节PTR[rbp-0x2],movzx是零扩展,movsxesiecxedxeax=intecx占用4字节,int的类型也占用4字节)。

因此,现在存储在变量c中的值0xFE已通过符号扩展转换为0xFFFFFFFE,存储在变量d的值0xFE已通过零扩展转换为0x000000FE0xFFFFFFFE4294967294%u时,打印的0xFFFFFE-2%d,打印的0x000000FE254%u、打印的0x000000FE则是254%d

4294967294的表示见下图。

-2的表示见下图。

现在您可以看到,当输出c或d的值时,使用%d和%u将它们打印出来会产生不同的结果。但是,这两种表示都引用了存储在内存中的相同值关键是如何选择解释c或d的值





相关问题
Fastest method for running a binary search on a file in C?

For example, let s say I want to find a particular word or number in a file. The contents are in sorted order (obviously). Since I want to run a binary search on the file, it seems like a real waste ...

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

Tips for debugging a made-for-linux application on windows?

I m trying to find the source of a bug I have found in an open-source application. I have managed to get a build up and running on my Windows machine, but I m having trouble finding the spot in the ...

Trying to split by two delimiters and it doesn t work - C

I wrote below code to readin line by line from stdin ex. city=Boston;city=New York;city=Chicago and then split each line by ; delimiter and print each record. Then in yet another loop I try to ...

Good, free, easy-to-use C graphics libraries? [closed]

I was wondering if there were any good free graphics libraries for C that are easy to use? It s for plotting 2d and 3d graphs and then saving to a file. It s on a Linux system and there s no gnuplot ...

Encoding, decoding an integer to a char array

Please note that this is not homework and i did search before starting this new thread. I got Store an int in a char array? I was looking for an answer but didn t get any satisfactory answer in the ...