由于位溢出表示为 -1?
Representation of -1 due to bit overflow?
嘿,我想弄清楚为什么 -1 << 4
(左)移位是 FFF0
在浏览和阅读网络后我开始知道 "negative" 数字有一个符号位,即1. 因为 "-1"
意味着额外的 1
位,即 (33) 位,这是不可能的,这就是为什么我们将 -1
视为 1111 1111 1111 1111 1111 1111 1111 1111
例如:-
#include<stdio.h>
void main()
{
printf("%x",-1<<4);
}
在这个例子中我们知道 –
Internal representation of -1 is all 1’s 1111 1111 1111 1111 1111 1111 1111 1111 in an 32 bit compiler.
When we bitwise shift negative number by 4 bits to left least significant 4 bits are filled with 0’s
Format specifier %x prints specified integer value as hexadecimal format
After shifting 1111 1111 1111 1111 1111 1111 1111 0000 = FFFFFFF0 will be printed.
以上内容的来源
http://www.c4learn.com/c-programming/c-bitwise-shift-negative-number/
首先,根据C标准,负值有符号变量左移的结果是未定义的。因此,从严格的语言律师的角度来看,“为什么 -1 << 4
导致 XYZ”这个问题的答案是“因为标准没有指定什么结果应该是。"
不过,您的特定编译器真正在做的是将 -1 的 two's-complement representation 左移,就好像该表示是无符号值一样。由于-1的32位二进制补码表示为0xFFFFFFFF
(或二进制为11111111 11111111 11111111 11111111
),左移4位的结果为0xFFFFFFF0
或11111111 11111111 11111111 11110000
。这是存储回(有符号)变量中的结果,该值是 -16 的二进制补码表示。如果您将结果打印为整数 (%d
),您将得到 -16。
这是大多数现实世界的编译器会做的,但不要依赖它,因为 C 标准不需要它。
首先,教程使用 void main
。 comp.lang.c
frequently asked question 11.15 在评估教程的质量时应该感兴趣:
Q: The book I've been using, C Programing for the Compleat Idiot, always uses void main()
.
A: Perhaps its author counts himself among the target audience. Many books unaccountably use void main()
in examples, and assert that it's correct. They're wrong, or they're assuming that everyone writes code for systems where it happens to work.
也就是说,示例的其余部分是不明智的。 C 标准 没有定义 有符号左移的行为。但是,允许 编译器实现 为标准有意开放的那些情况定义行为。例如 GCC does define 那
- 所有有符号整数都具有 two's-complement 格式
<<
在负符号数上定义明确,>>
就像符号扩展一样工作。
因此,GCC 上的 -1 << 4
保证会产生 -16
;这些数字的位表示,给定 32 位 int
分别是 1111 1111 1111 1111 1111 1111 1111 1111
和 1111 1111 1111 1111 1111 1111 1111 0000
。
现在,这里有 另一个 未定义的行为:%x
需要一个 unsigned int
的参数,但是你传递的是 signed int
,其值无法在 unsigned int
中表示。但是,GCC 上的行为 / 常见 libc 的 最有可能 是带符号整数的字节被解释为无符号整数,1111 1111 1111 1111 1111 1111 1111 0000
二进制,十六进制是 FFFFFFF0
.
但是,一个可移植的 C 程序真的应该永远不会
- 假设二进制补码表示 - 当表示很重要时,使用
unsigned int
甚至 uint32_t
- 假设负数上的
<<
或 >>
具有特定行为
- 使用带符号的
%x
- 写
void main
.
具有定义行为的相同用例的可移植(C99、C11、C17)程序将是
#include <stdio.h>
#include <inttypes.h>
int main(void)
{
printf("%" PRIx32, (uint32_t)-1 << 4);
}
嘿,我想弄清楚为什么 -1 << 4
(左)移位是 FFF0
在浏览和阅读网络后我开始知道 "negative" 数字有一个符号位,即1. 因为 "-1"
意味着额外的 1
位,即 (33) 位,这是不可能的,这就是为什么我们将 -1
视为 1111 1111 1111 1111 1111 1111 1111 1111
例如:-
#include<stdio.h>
void main()
{
printf("%x",-1<<4);
}
在这个例子中我们知道 –
Internal representation of -1 is all 1’s 1111 1111 1111 1111 1111 1111 1111 1111 in an 32 bit compiler.
When we bitwise shift negative number by 4 bits to left least significant 4 bits are filled with 0’s
Format specifier %x prints specified integer value as hexadecimal format
After shifting 1111 1111 1111 1111 1111 1111 1111 0000 = FFFFFFF0 will be printed.
以上内容的来源 http://www.c4learn.com/c-programming/c-bitwise-shift-negative-number/
首先,根据C标准,负值有符号变量左移的结果是未定义的。因此,从严格的语言律师的角度来看,“为什么 -1 << 4
导致 XYZ”这个问题的答案是“因为标准没有指定什么结果应该是。"
不过,您的特定编译器真正在做的是将 -1 的 two's-complement representation 左移,就好像该表示是无符号值一样。由于-1的32位二进制补码表示为0xFFFFFFFF
(或二进制为11111111 11111111 11111111 11111111
),左移4位的结果为0xFFFFFFF0
或11111111 11111111 11111111 11110000
。这是存储回(有符号)变量中的结果,该值是 -16 的二进制补码表示。如果您将结果打印为整数 (%d
),您将得到 -16。
这是大多数现实世界的编译器会做的,但不要依赖它,因为 C 标准不需要它。
首先,教程使用 void main
。 comp.lang.c
frequently asked question 11.15 在评估教程的质量时应该感兴趣:
Q: The book I've been using, C Programing for the Compleat Idiot, always uses
void main()
.A: Perhaps its author counts himself among the target audience. Many books unaccountably use
void main()
in examples, and assert that it's correct. They're wrong, or they're assuming that everyone writes code for systems where it happens to work.
也就是说,示例的其余部分是不明智的。 C 标准 没有定义 有符号左移的行为。但是,允许 编译器实现 为标准有意开放的那些情况定义行为。例如 GCC does define 那
- 所有有符号整数都具有 two's-complement 格式
<<
在负符号数上定义明确,>>
就像符号扩展一样工作。
因此,GCC 上的 -1 << 4
保证会产生 -16
;这些数字的位表示,给定 32 位 int
分别是 1111 1111 1111 1111 1111 1111 1111 1111
和 1111 1111 1111 1111 1111 1111 1111 0000
。
现在,这里有 另一个 未定义的行为:%x
需要一个 unsigned int
的参数,但是你传递的是 signed int
,其值无法在 unsigned int
中表示。但是,GCC 上的行为 / 常见 libc 的 最有可能 是带符号整数的字节被解释为无符号整数,1111 1111 1111 1111 1111 1111 1111 0000
二进制,十六进制是 FFFFFFF0
.
但是,一个可移植的 C 程序真的应该永远不会
- 假设二进制补码表示 - 当表示很重要时,使用
unsigned int
甚至uint32_t
- 假设负数上的
<<
或>>
具有特定行为 - 使用带符号的
%x
- 写
void main
.
具有定义行为的相同用例的可移植(C99、C11、C17)程序将是
#include <stdio.h>
#include <inttypes.h>
int main(void)
{
printf("%" PRIx32, (uint32_t)-1 << 4);
}