一、內核對象數據類型
1.1 C語言類型(int)
char、short、int、long long在不同的平臺上大小不變。
linux內核版本信息。long、ptr(指針)平臺不同其大小不同,但二者的大小始終相同。
char的符號問題:
大多數平臺上char默認是signed,但有些平臺上默認是 unsigned。
char i = -1; 大部分平臺上i是-1,有些平臺上是255。
Linux 內核,應該使用:signed char i = -1; ? unsigned char i = 255;
1.2 確定大小的類型(u32)
u8、u16、u32、u64、?s8、s16、s32、s64是linux內核確定大小的類型。
__u8等式linux用戶態確定大小的類型。(頭文件linux/types.h)
java并發包常用類,uint8_t、uint32_t是新編譯器支持的C99標準確定大小的類型,可以跨平臺。
1.3 特定內核對象的類型(pid_t)
進程標識符使用pid_t類型,而不使用int,屏蔽了實際的數據類型中任何可能的差異。
特定內核對象的類型,打印時,不太好選擇printk或printf的輸出格式:
UNIX/LINUX、1. ?一些平臺上排除的警告,在另一平臺上可能會出現(size_t在一些平臺上是unsigned long,在一些平臺上是unsigned int)。
2. 將其強制轉換成可能的最大類型,然后用響應的格式打印輸出。
二、字節序
2.1 大端、小端
vim 上一頁下一頁、數值0x01020304,內存從低到高依次存儲:04 03 02 01 為小端。 存儲順序反過來為大端)
數值0x00000001,內存從低到高依次存儲:01 00 00 00 為小端。
2.2 轉換函數
u32?__cpu_to_be32(u32); ? ?/* 把cpu字節序轉為大端字節序?*/
linux最新內核?u32?__be32_to_cpu(u32);? ? /* 把大端字節序轉為cpu字節序?*/
u32?__cpu_to_le32(u32); ? ? ?/* 把cpu字節序轉為小端字節序?*/
u32?__le32_to_cpu(u32); ? ? ?/* 把小端字節序轉為cpu字節序?*/
在頭文件中
linux內核版本號、2.3 檢測本機大端小端的代碼
#include
#include
/*int is_little_endian()
{
const static union
{
unsigned int i;
unsigned char c[4];
}u = { 0x00000001 };
return u.c[0];
}*/
int is_little_endian()
{
int i = 1;
return *(char*)&i;
}
int main(int argc, char*argv[])
{
if (is_little_endian())
printf("little endian.\n");
else
printf("big endian.\n");
return 0;
}
三、數據對齊
3.1 數據對齊
對齊:如果一個變量的內存地址正好是它長度的整數倍,它就被稱作是自然對齊的。
3.2?數據未對齊印發的問題
一些平臺不能訪問未對其的數據,一些平臺可以訪問未對齊的數據,但是效率很低。
用指針進行類型轉換引發的未對齊:
char dog[10]; //是對齊的
char *p = &dog[1];
long l = *(long*)p; //l是未對齊的
3.3 盡量保證數據對齊
為了實現跨平臺,應盡量讓數據自然對齊。
編譯器會悄悄的插入數據保證struct的自然對齊:
1. 下面的代碼,沒有__attribute__((packed)),長度為16;
2. 下面的代碼,有__attribute__((packed)),長度為10;
3. ?__attribute__((packed))不讓編譯器對struct進行填充,以保證其自然對齊(有時候我們需要這樣的數據)。
#include
#include
#include
int main(int argc, char*argv[])
{
struct
{
__u16 i;
__u64 j;
}__attribute__((packed)) u;
printf("struct u len:%d\n", sizeof(u));
return 0;
}
3.4 訪問未對齊的數據
應該使用下面的宏:
#include
get_unaligned(ptr)
put_unaligned(var, ptr)
四、其他有關可移植性的問題
避免使用顯示的常量值
4.1 時間間隔
使用HZ代表一秒。
不能假定每秒就1000個jiffies。
與msec毫秒對應的jiffies數目總是msec*HZ/1000。
4.2 頁大小
頁大小為PAGE_SIZE個字節,而不是4KB。
分配16KB的空間臨時存儲數據,如下:
#include
int order = get_order(16*1024);
buf = get_free_pages(GFP_KERNEL, order);
4.3 指針和錯誤值
許多內核函數通過把錯誤值編碼到一個指針值中來返回錯誤信息,這種函數必須小心使用,它的返回值不能簡單地和NULL比較。
見
#include
static struct task_struct *kapmd_task;
kapmd_task = kthread_create(apm, NULL, "kapmd");
if (IS_ERR(kapmd_task)) {
printk(KERN_ERR "apm: disabled - Unable to start kernel "
"thread.\n");
err = PTR_ERR(kapmd_task);
kapmd_task = NULL;
remove_proc_entry("apm", NULL);
return err;
}
4.4 其他
處理器排序(rmb()、wmb())、SMP、內核搶占、高端內存
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态