我正在解释 linux 内核模块生成的中间代码。但我无法理解以下 pci_set_dma_mask
的代码行
if ((err = pci_set_dma_mask(pdev, (((32) == 64) ? ~0ULL : ((1ULL<<(32))-1))))) {<br/>
(void)((NETIF_MSG_PROBE & nic->msg_enable) && printk("<3>" "e100" ": " "%s: %s: "
"No usable DMA configuration, aborting.\n", nic->netdev->name, <strong>func</strong>));
}
我的理解是,因为 32 != 64,((1ULL<<(32))-1)
将执行。但是 1ULL
是什么样的值呢? ?当我们下类时内部发生了什么 1ULL
32次?有人可以提供一些代码示例来理解这一点吗?提前致谢
最佳答案
多余的括号和琐碎的条件 (32) == 64
显示这是生成的代码,可能是运行预处理器的结果。该条件测试某个东西是 32 位还是 64 位,并且已经为那个东西是 32 位的系统生成了代码。
在 64 位系统上,值 ~0ULL
用来。随着ULL
后缀,常量类型为unsigned long long
,它在 Linux 内核支持的所有平台上都是 64 位类型(标准 C 指定 unsigned long long
是 64 位或更大,但几乎所有系统都将它作为 64 位)。 ~
运算符采用按位补码,因此结果是数字 264-1,即一个 64 位常量,其二进制表示为全位一。在十六进制中,即 0xffffffffffffffff
.
代码使用~0ULL
的原因而不是 ~0
是在~0
, 常量 0
是一个 int
,这是 Linux 内核支持的所有平台上的 32 位类型。 ~
运算符应用于此将产生一个全位为一的 32 位值,即 0xffffffff
十六进制,即数字 232-1。转换为 64 位值时,数值保持不变 — 不是全 64 位常量。
在 32 位系统上,代码使用 1ULL<<(32))-1
.第一1ULL
是一个 64 位值; 1ULL << 32
将其左移 32,这意味着将数值乘以 232,得到数字 232,或十六进制 0x100000000
.减去 1 得到 232,即 0xffffffff
(全 32 位一常数)。
对 unsigned long long
进行操作这里也是必需的,因为没有为 32 位值定义左移 32 位。标准 C 说 x << 32
如果 x
的类型是未定义的行为是 32 位或更少的类型。实际上,在许多系统上,用于 32 位类型移位的处理器指令采用 0…31 和 1 << 32
范围内的移位量。将被编译为与 1 << 0
相同的代码(包装模 32),产生 1 而不是 232。
关于c - 了解 Linux 模块代码片段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38960428/