使用asm/div64.h中宏do_div
#include <asm/div64.h>
unsigned long long x,y,result; unsigned long mod; mod = do_div(x,y); result = x;
64 bit division 結(jié)果保存在x中;余數(shù)保存在返回結(jié)果中。
問題】 編譯Linux下面的代碼,經(jīng)常會遇到這種錯誤: undefined reference to `__udivdi3' 【解決過程】 之前遇到過幾次了,都是類似的原因?qū)е麓藛栴}的。后來才了解,其根本原因: 嵌入式中,32位系統(tǒng)中(目前多數(shù)系統(tǒng)都是,比如ARM的片子),對于普通的a除以b(b為32位): (1)當(dāng)a為32位,Linux 內(nèi)核中,常用uint32_t 類型,可以直接寫為 a/b (2)但是,對于a是64位,uint64_t的時候,就要用到專門的除操作相關(guān)的函數(shù),linux內(nèi)核里面一般為 do_div(n, base),注意,此處do_div得到的結(jié)果是余數(shù),而真正的a/b的結(jié)果,是用a來保存的。 do_div(n,base)的具體定義,和當(dāng)前體系結(jié)構(gòu)有關(guān),對于arm平臺,在 arch/arm/include\asm\div64.h 其實現(xiàn)很復(fù)雜,感興趣的自己去代碼里看吧,這里不多說了。 因此,如果你當(dāng)前寫代碼,a/b,如果a是uint64_t類型,那么一定要利用do_div(a,b),而得到結(jié)果a, 而不能簡單的用a/b,否則編譯可以正常編譯,但是最后鏈接最后出錯,會提示上面的那個錯誤: undefined reference to "__udivdi3" 【解決方法】 知道原因,就好辦了。辦法就是,去你代碼里面找到對應(yīng)的用到除法的地方,即類似于a/b的地方,其中被除數(shù)a為64位,Linux中一般用用 uint64_t,將a/b用do_div(a,b)得到的a去代替(注意,不是直接用do_div()得到真正a除b后的結(jié)果,因為 do_div(a,b)得到的是余數(shù),囧。。。),即可,而具體寫其他,就顯得很麻煩。此處,我們可以借鑒Linux中\(zhòng)fs\yaffs2 \yaffs_fs.c中的宏:
static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size) 來自己也去封裝一個支持64位數(shù)的除法的函數(shù),不過,Linux內(nèi)核就是好,早已經(jīng)幫我們實現(xiàn)了對應(yīng)的64位的unsingned和signed兩個函數(shù): static inline u64 div_u64(u64 dividend, u32 divisor);
static inline s64 div_s64(s64 dividend, s32 divisor); #include <linux/math64.h> 總結(jié)一下就是: 1.先包含頭文件: 2.然后用(a,b)得到a/b的結(jié)果即可。 【提示】 如果需要在進行64位除數(shù)的時候,同時得到余數(shù)remainder,可以直接用
static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder); 【引用】 If you've encountered an error message like this Unknown symbol __udivdi3Unknown symbol __umoddi3Unresolved symbol __udivdi3Unresolved symbol __umoddi3
you most likely want to make a 64 bit division, which is not supported by default in linux kernel space. #include <asm/div64.h>unsigned long long x, y, result;unsigned long mod;mod = do_div(x, y);result = x;
If you want to calculate x / y with do_div(x, y), the result of the division is in x, the remainder is returned from the do_div function. |
|