在 K&R ANSI C 书的 A.7.4.5 节(一元减号运算符)中指出:
...无符号数量的负数是通过从提升类型的最大值中减去提升值并加一来计算的;...
这个具体是怎么计算的?你能举一个简短的C例子吗?
我不明白这怎么会产生负数,比如 200u:从任何整数类型(有符号或无符号)的最大值中减去 200,加 1 不会导致 -200。
我知道一元减号的作用——问题是我看不到结果是如何根据描述计算的。
在 K&R ANSI C 书的 A.7.4.5 节(一元减号运算符)中指出:
...无符号数量的负数是通过从提升类型的最大值中减去提升值并加一来计算的;...
这个具体是怎么计算的?你能举一个简短的C例子吗?
我不明白这怎么会产生负数,比如 200u:从任何整数类型(有符号或无符号)的最大值中减去 200,加 1 不会导致 -200。
我知道一元减号的作用——问题是我看不到结果是如何根据描述计算的。
无符号值不能为负数,因此 -200 不是可能的结果。
它的意思是,如果UINT_MAX
你的系统上是 65535,那么结果是:
unsigned a = 200;
unsigned b = -a;
long c = -a;
b
将在和中留下 65336 c
。
如果您的系统有UINT_MAX > LONG_MAX
(通常因为int
和long
大小相同),您将需要使用long long
for c
(尽管请注意,甚至没有任何保证足够长)。
如果你不理解这个细节(否定一个无符号数的结果是另一个,必然是正的,无符号数)可能会导致一些意想不到的效果。例如,在此代码中,第一个示例打印"true"
,但第二个示例打印"false"
:
int a = 200;
unsigned b = 200;
if (-a < 100) printf("true\n"); else printf("false\n");
if (-b < 100) printf("true\n"); else printf("false\n");
(请注意,我们不会将否定运算符的结果存储在任何地方 - 这不是问题)。
显然,您在引用的描述中错过了unsigned一词。这是本案的关键词。在 C 语言中,无符号数量的“负”仍然是无符号的,这意味着它并不是真正的负数。根据定义,无符号值永远不能是负数。它们总是正数或 0。C 中无符号值的算术是模算术,或者简单地说,当您对它们执行算术运算时,无符号量“环绕”。一元否定也不例外。计算-n
whenn
是 unsigned 与计算 没有什么不同0 - n
。如果n
是unsigned int
并且它的值是200
预期的结果不是-200
,而是UINT_MAX - 200 + 1
,这正是报价告诉你的。
对无符号整数类型的操作使用模运算。算术模 m 与常规算术非常相似,除了结果是除以 m 时的正余数,如果您在学校没有遇到过(更多详细信息,请参阅Wikipedia 文章。例如,7 - 3模 10 是 4,而 3 - 7 模 10 是 6,因为 3 - 7 是 -4,除以 10 得出商为 -1,余数为 6(也可以用商 0 和-4 的余数,但在模算术中不是这样工作的任何情况下的价值。
现在,一元减号表示负数,它不是模 m 的有效值。在这种情况下,我们知道它在 0 和 m-1 之间,因为我们从一个无符号整数开始。因此,我们正在考虑将 -k 除以 m。由于一个可能的值是 0 的商和 -k 的余数,另一个可能是 -1 的商和 mk 的余数,所以正确答案是 mk。
C 中的无符号整数通常由最大值描述,而不是模数,这意味着无符号 16 位数通常被描述为 0 到 65535,或者最大值为 65535。这是通过指定来描述值m-1 而不是 m。
What the quotation you have says that the value of a negative is taken by subtracting it from m-1 and then adding 1, so -k is m - 1 - k + 1, which is m - k. The description is a little roundabout, but it specifies the correct result in terms of the pre-existing definitions.
让我们保持简单,看一个无符号字符... 8 位,值范围为 0-255。
什么是 (unsigned char)-10 以及它是如何计算的?
根据您引用的 K & R 声明,我们有:
-10 的提升值是10从提升类型的最大值中减去255 加上1 = 246
所以 (unsigned char)-10 实际上是 246。这有意义吗?