Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
负数逻辑右移在c语言中的实现_C_Operators_Bit Shift - Fatal编程技术网

负数逻辑右移在c语言中的实现

负数逻辑右移在c语言中的实现,c,operators,bit-shift,C,Operators,Bit Shift,有没有一种简单的方法可以在c语言中对负数执行逻辑右移,就像我们在>>中对算术右移所做的那样?右移负数调用c语言中的实现定义行为。将发生的事情不是由标准指定的,而是由编译器指定。因此,它可以导致算术移位,或者逻辑移位,或者完全其他的东西(比如旋转,尽管我从来没听说过)。除非阅读特定的编译器文档,否则无法知道或假设哪种方法适用于编译器 但是,无符号数字始终使用逻辑移位。因此,如果您希望对负数进行逻辑移位(可移植),则在移位之前转换为无符号: int32_t i = -1; i = (int32_t

有没有一种简单的方法可以在c语言中对负数执行逻辑右移,就像我们在>>中对算术右移所做的那样?

右移负数调用c语言中的实现定义行为。将发生的事情不是由标准指定的,而是由编译器指定。因此,它可以导致算术移位,或者逻辑移位,或者完全其他的东西(比如旋转,尽管我从来没听说过)。除非阅读特定的编译器文档,否则无法知道或假设哪种方法适用于编译器

但是,无符号数字始终使用逻辑移位。因此,如果您希望对负数进行逻辑移位(可移植),则在移位之前转换为无符号:

int32_t i = -1;

i = (int32_t) ((uint32_t)i >> n); // guaranteed to give logical shift
类似地,如果要保证算术移位:

int32_t i = -1;
bool negative = i < 0;

if(negative)
{
  i = -i;
}

i = (int32_t) ((uint32_t)i >> n);

if(negative)
{
  i = -i;
}
int32\tuti=-1;
bool阴性=i<0;
如果(否定)
{
i=-i;
}
i=(int32_t)((uint32_t)i>>n);
如果(否定)
{
i=-i;
}

右移负数调用C中实现定义的行为。标准没有指定将发生什么,而是留给编译器指定。因此,它可以导致算术移位,或者逻辑移位,或者完全其他的东西(比如旋转,尽管我从来没听说过)。除非阅读特定的编译器文档,否则无法知道或假设哪种方法适用于编译器

但是,无符号数字始终使用逻辑移位。因此,如果您希望对负数进行逻辑移位(可移植),则在移位之前转换为无符号:

int32_t i = -1;

i = (int32_t) ((uint32_t)i >> n); // guaranteed to give logical shift
类似地,如果要保证算术移位:

int32_t i = -1;
bool negative = i < 0;

if(negative)
{
  i = -i;
}

i = (int32_t) ((uint32_t)i >> n);

if(negative)
{
  i = -i;
}
int32\tuti=-1;
bool阴性=i<0;
如果(否定)
{
i=-i;
}
i=(int32_t)((uint32_t)i>>n);
如果(否定)
{
i=-i;
}

逻辑右移是通过在移位之前将
int
值强制转换为
无符号
来完成的:

int lsr(int n, int shift) {
    return (int)((unsigned)n >> shift);
}
算术右移不能直接使用C中负值上的
运算符进行dpne,因为其效果是由实现定义的。以下是一个简单的替代方案,不需要测试,它为2s补码体系结构上的所有值复制符号位:

int asr(int n, int shift) {
    unsigned u = (unsigned)n;
    return (int)((u >> shift) | ~(((u & (unsigned)INT_MIN) >> shift) - 1));
}
下面是一个简单的测试程序:

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>

int lsr(int n, int shift) {
    return (int)((unsigned)n >> shift);
}

int asr(int n, int shift) {
    unsigned u = (unsigned)n;
    return (int)((u >> shift) | ~(((u & (unsigned)INT_MIN) >> shift) - 1));
}

int main(int argc, char *argv[]) {
    int n = (argc < 2) ? -2 : strtol(argv[1], NULL, 0);
    int shift = (argc < 3) ? 2 : strtol(argv[2], NULL, 0);

    printf("%d >> %d = %d\n", n, shift, asr(n, shift));
    printf("%d >>> %d = %d\n", n, shift, lsr(n, shift));

    return 0;
}
#包括
#包括
#包括
整数lsr(整数n,整数移位){
返回(int)((无符号)n>>移位);
}
内部asr(内部n,内部移位){
无符号u=(无符号)n;
返回(int)((u>>移位)| ~((u&(无符号)int_MIN)>>移位)-1);
}
int main(int argc,char*argv[]){
int n=(argc<2)?-2:strtol(argv[1],NULL,0);
int-shift=(argc<3)?2:strtol(argv[2],NULL,0);
printf(“%d>>%d=%d\n”,n,shift,asr(n,shift));
printf(“%d>>>%d=%d\n”,n,shift,lsr(n,shift));
返回0;
}

逻辑右移是通过在移位之前将
int
值强制转换为
无符号
来完成的:

int lsr(int n, int shift) {
    return (int)((unsigned)n >> shift);
}
算术右移不能直接使用C中负值上的
运算符进行dpne,因为其效果是由实现定义的。以下是一个简单的替代方案,不需要测试,它为2s补码体系结构上的所有值复制符号位:

int asr(int n, int shift) {
    unsigned u = (unsigned)n;
    return (int)((u >> shift) | ~(((u & (unsigned)INT_MIN) >> shift) - 1));
}
下面是一个简单的测试程序:

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>

int lsr(int n, int shift) {
    return (int)((unsigned)n >> shift);
}

int asr(int n, int shift) {
    unsigned u = (unsigned)n;
    return (int)((u >> shift) | ~(((u & (unsigned)INT_MIN) >> shift) - 1));
}

int main(int argc, char *argv[]) {
    int n = (argc < 2) ? -2 : strtol(argv[1], NULL, 0);
    int shift = (argc < 3) ? 2 : strtol(argv[2], NULL, 0);

    printf("%d >> %d = %d\n", n, shift, asr(n, shift));
    printf("%d >>> %d = %d\n", n, shift, lsr(n, shift));

    return 0;
}
#包括
#包括
#包括
整数lsr(整数n,整数移位){
返回(int)((无符号)n>>移位);
}
内部asr(内部n,内部移位){
无符号u=(无符号)n;
返回(int)((u>>移位)| ~((u&(无符号)int_MIN)>>移位)-1);
}
int main(int argc,char*argv[]){
int n=(argc<2)?-2:strtol(argv[1],NULL,0);
int-shift=(argc<3)?2:strtol(argv[2],NULL,0);
printf(“%d>>%d=%d\n”,n,shift,asr(n,shift));
printf(“%d>>>%d=%d\n”,n,shift,lsr(n,shift));
返回0;
}

Hmm使用
int32\u t/uint32\u t
确实提供了保证的逻辑移位,但是,尽管这些类型很常见,但它们是可选的,因此在一定程度上限制了可移植性。由于
i=-i,第二个“保证算术移位”是-2147483648的UB,但可能按预期工作。@chux我不会担心编译器不支持stdint.h。这样的编译器需要尽快从市场上删除,如果我们可以通过编写依赖stdint.h的代码来提供帮助,那就更好了。该标准所说的与此无关,程序员应该要求编译器是适用于现实世界的有用工具。@chux变量具有INT_MIN值并被转换的情况不是UB,而是实现定义的,6.3.1.3/3:否则,新类型将被签名,并且无法在其中表示值;要么结果是实现定义的,要么引发实现定义的信号。“我的评论不是调用UB的
INT\u MIN
转换,而是
-
操作,即
INT
溢出-即UB。我同意编写依赖int8、16、32、64的代码,但也承认它确实限制了某些情况下的可移植性——也许更好。使用
int32\u t/uint32\u t
可以保证逻辑移位,但是,尽管这些类型很常见,但它们是可选的,因此在一定程度上限制了可移植性。由于
i=-i,第二个“保证算术移位”是-2147483648的UB,但可能按预期工作。@chux我不会担心编译器不支持stdint.h。这样的编译器需要尽快从市场上删除,如果我们可以通过编写依赖stdint.h的代码来提供帮助,那就更好了。该标准所说的与此无关,程序员应该要求编译器是适用于现实世界的有用工具。@chux变量具有INT_MIN值并被转换的情况不是UB,而是实现定义的,6.3.1.3/3:否则,新类型将被签名,并且无法在其中表示值;要么结果是实现定义的,要么发出实现定义的信号。”我的注释不是调用UB的
INT\u MIN
转换,而是
-
opera