C 如何在Linux内核中划分两个64位数字?
一些将该部分四舍五入以演示的代码(C语法): 现在,如果这是用户空间,我们可能甚至不会注意到我们的编译器正在为这些操作符生成代码(例如,C 如何在Linux内核中划分两个64位数字?,c,linux,64-bit,C,Linux,64 Bit,一些将该部分四舍五入以演示的代码(C语法): 现在,如果这是用户空间,我们可能甚至不会注意到我们的编译器正在为这些操作符生成代码(例如,divdi3()for division)。很可能我们连自己都不知道就链接到了libgcc。问题是内核空间不同(例如,nolibgcc)。怎么办 在Google上爬行一段时间,注意几乎每个人都会处理未签名的变体: #define UINT64 long long int #define UINT32 long int UINT64 divRound(UINT6
divdi3()
for division)。很可能我们连自己都不知道就链接到了libgcc
。问题是内核空间不同(例如,nolibgcc
)。怎么办
在Google上爬行一段时间,注意几乎每个人都会处理未签名的变体:
#define UINT64 long long int
#define UINT32 long int
UINT64 divRound(UINT64 dividend, UINT64 divisor)
{
UINT32 quotient1 = dividend / divisor;
UINT32 modResult = dividend % divisor;
UINT32 multResult = modResult * 2;
UINT32 quotient2 = multResult / divisor;
UINT64 result = quotient1 + quotient2;
return ( result );
}
我知道如何解决这个问题:使用asm/div64.h中的do_div()
覆盖udivdi3()
和umoddi3()
。做对了吗?错。Signed与unsigned不同,sdivdi3()
不只是调用udivdi3()
,它们是独立的函数,这是有原因的
你解决这个问题了吗?你知道有哪个图书馆可以帮我做这件事吗?我真的被卡住了,所以无论你在这里看到什么,我现在不知道的,都会很有帮助
谢谢,
乍得ldiv
编辑:重读标题,所以您可能希望忽略此内容。或者没有,这取决于它是否有合适的非库版本。这是我真正天真的解决方案。您的里程可能会有所不同 保留一个符号位,即
符号(被除数)^sign(除数)
。(或*
,或/
,如果您将符号存储为1和-1,而不是false和true。基本上,如果其中一个为负,则为负;如果没有或两者都为负,则为正。)
然后,对两者的绝对值调用无符号除法函数。然后将标志钉回结果上
另外,这实际上是\uuu divdi3
在libgcc2.c
中实现的方式(来自GCC4.2.3,安装在我的Ubuntu系统上的版本)。我刚查过。:-) 我认为(至少找不到办法)在这种情况下不起作用,因为do_div()实际上改变了股息。获取绝对值意味着一个临时变量,其值将改变我需要的方式,但不能从我的\uu divdi3()覆盖中传递出去
在这一点上,除了模仿do\u div()所使用的技术外,我看不到任何方法可以绕过\u divdi3()的参数按值签名
这可能看起来像是我在向后弯腰,应该想出一个算法来进行我实际需要的64位/32位除法。然而,这里增加的复杂性是,我有一堆使用“/”运算符的数字代码,需要遍历这些代码,并用我的函数调用替换每个“/”
不过,我已经迫不及待要这么做了
谢谢你的跟进,
Chad早在内核v2.6.22中就引入了此功能。最近,我们为每一个要使用的代码都提供了一份libgcc实现的副本(在lib/libgcc IIRC下)。但内核中的旧方法实际上是do_div()或div64.c中的相应函数。
#define UINT64 long long int
#define UINT32 long int
UINT64 divRound(UINT64 dividend, UINT64 divisor)
{
UINT32 quotient1 = dividend / divisor;
UINT32 modResult = dividend % divisor;
UINT32 multResult = modResult * 2;
UINT32 quotient2 = multResult / divisor;
UINT64 result = quotient1 + quotient2;
return ( result );
}