Golang中如何对int32类型进行负数左移操作?[v1.21]

Golang中如何对int32类型进行负数左移操作?[v1.21] 我想在 Go 语言中复制以下 C 代码:

uint32_t xx = 0x1FA19141;
uint32_t n = 1759730200;
uint32_t temp1 = xx << (32 - n);

我的实现如下:

var n int = 1759730200
temp := int32(32 - n)
temp1 := int32(xx << temp)

然而,Go 语言似乎不允许负数的移位操作。

我遇到了运行时错误:panic: runtime error: negative shift amount

根据源文件 go/expressions.c,由于某些原因,Go 似乎不允许此操作:

if (mpz_sgn(val) < 0)
{
  this->report_error(_("negative shift count"));
....
}

如何强制进行负数的左移操作?有人能帮我解决这个问题吗?


更多关于Golang中如何对int32类型进行负数左移操作?[v1.21]的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

我也感到困惑

更多关于Golang中如何对int32类型进行负数左移操作?[v1.21]的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


  • 这意味着即使最高有效位(符号位)被移出,它仍然被视为负数。

shift left by negative numbe

如果移位数为负数,右移会怎样? 例如:

if temp > 0 {
 temp1  := int32(xx << temp)
} else {
 temp1 := int32(xx >> int32(math.Abs(temp)))
}

这行不通,因为 math.Abs 期望的是浮点数。

即使使用以下代码:

if temp > 0 {
 temp1  := int32(xx << temp)
} else {
 temp1 := int32(xx >> int32(math.Abs(float64(temp))))
}

这也会导致 temp1 为 0,因为移位值太长了。

我不确定为什么在 C 和 clang+11 编译器中这能完美运行。

在Go语言中,移位操作确实不允许负数的移位计数,这是语言规范明确规定的。要复制C代码中的行为,你需要手动处理负数的移位情况。

C代码中的 xx << (32 - n)(32 - n) 为负数时,实际上执行的是右移操作。在C语言中,负数的左移是未定义行为,但你的代码似乎期望特定的行为。

以下是正确的Go实现:

package main

import (
	"fmt"
)

func main() {
	var xx uint32 = 0x1FA19141
	var n uint32 = 1759730200
	
	// 计算移位量
	shift := 32 - n
	
	// 手动处理负移位的情况
	var temp1 uint32
	if shift > 31 {
		// 移位量大于31,结果为0
		temp1 = 0
	} else if shift < 0 {
		// 负移位转换为右移
		temp1 = xx >> (-shift)
	} else {
		// 正常左移
		temp1 = xx << shift
	}
	
	fmt.Printf("xx: 0x%X\n", xx)
	fmt.Printf("n: %d\n", n)
	fmt.Printf("shift: %d\n", int32(shift))
	fmt.Printf("temp1: 0x%X\n", temp1)
}

或者,使用更简洁的位操作方式:

func shiftLeftWithNegative(xx uint32, shift int32) uint32 {
	if shift < 0 {
		return xx >> (-shift)
	}
	return xx << shift
}

// 使用示例
xx := uint32(0x1FA19141)
n := uint32(1759730200)
shift := int32(32 - int32(n))
temp1 := shiftLeftWithNegative(xx, shift)

如果你需要完全模拟C语言中可能出现的未定义行为(虽然不推荐),可以使用unsafe包:

import (
	"unsafe"
)

func cStyleShift(xx uint32, shift int32) uint32 {
	// 注意:这模拟了C的未定义行为,可能不是可移植的
	if shift < 0 {
		// 转换为有符号整数进行右移
		return uint32(int32(xx) >> (-shift))
	}
	return xx << shift
}

关键点:

  1. Go语言规范明确禁止负数的移位计数
  2. 负数的左移在逻辑上等价于右移
  3. 需要手动处理移位边界检查(Go的移位操作会自动处理大于31的移位量,结果为0)

根据你的具体需求,第一种实现方式是最安全且符合Go语言习惯的。

回到顶部