2010年1月27日 星期三

[語言] __attribute__

這東西的用法很特別,來自GNU C,挑幾個我看過
OR用過的做ㄧ下筆記

會用跟搞清楚~~還真的有點距離。
用來檢查函數的格式:
可以叫complier幫你檢查如果你的函數長的像printf 或scanf 等等

example:

#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

int bbprintf(int i, const char *fmt, ...) __attribute__((format(printf,2,3)));

int bbprintf(int i, const char *fmt, ...)
{
    va_list args;

    printf("i = %d \n", i);

    va_start(args, fmt);
    return vfprintf(stdout, fmt, args);
}


int main()
{
    bbprintf(10 ,"num = %d \n", 5);
}

這樣他就會幫你把bbprintf()用printf檢查一番
例如: 故意把%d 換成%s

warning: format '%s' expects type 'char *', but argument 3 has type 'int'

指令說明:
format(printf,2,3)
第一格:printf -> 依照printf的樣子檢查
第二格:2 -> const char *fmt 這是第二欄
第三格:3 -> ... 這是第三欄

之前有遇過類似的問題,如果可以這個檢查應該可以避掉

--
這個也可以避掉void function 的呼叫被放在有return 的位置,
避免 complier 跟你靠腰

void myexit(void)  __attribute__ ((__noreturn__));

void myexit()
{
    printf("YA \n");
    exit(1);  <--- 不能省 不然你會看到更奇怪的靠腰,原因是程式需要在這裡終止。
}

int main()
{
    int n = 1;
    if( n > 0 )
    {
        myexit();
    }else
        return 0;
}

是意思是告訴complier myexit是沒有回傳的function 就算他放在需要回傳的function裡,也請睜ㄧ隻眼閉一隻眼。
abort() 就是用同樣的方式宣告。

否則你會看到以下的訊息
warning: control reaches end of non-void function

以上在complier時記得加上  -Wall 才看到的

當然還有
const
aligned
packed
使用該屬性可以使得變量或者結構體成員使用最小的對齊方式

還很多,packed有看過,沒用到就先不記錄了。

2010年1月22日 星期五

[Linux] 麗娜思小妹妹幫你換心臟囉

小妹妹要有強壯的心靈,才不會被奇怪的大哥哥拐走!!!
又可以幫她脫光光了 YA

最近想弄點東西,抓了kernel source 來幫麗納思小妹妹換個強壯的心靈!!!

按照慣例

這是神級的官網
http://www.kernel.org/

版本這次用的是
2.6.32.4
雖然工作機是Unbuntu不過這次要換的是Debian小B機~

首先準備
解開linux source 需要bzip2 (debian 預設沒有裝)
make menuconfig 需要ncurses-devel,ncurses-devel 需要叫做libncurses5-dev (靠~debian 預設還是沒有裝,不過我就是喜歡她這點>////////< 不穿比較好)

  • 編譯步驟
Linux Source 的Makefile有寫HELP說明所以先
make help <-- Makefile 有寫了哪些目標可以被make

就會發現下面很有用的訊息:
make mrproper <-- 清光設定檔包跨 .config + make clean
make clean <-- 就是 clean

make menuconfig <-- 選菜
make oldconfig <-- 只有列出新的來選

make all <-- 等於make vmlinux, make modules, make bzImage

make vmlinux <-- 作出沒有壓縮的核心,在source 根目錄會看到
make modules <-- 作出核心用的模組,以後可以insmod
make bzImage <-- 作出壓縮過的核心,在arch/i386/boot/bzImage,或是arch/i386/boot/bzImage -> ../../x86/boot/bzImage

make module_install <--會幫忙拷貝module到目錄/lib/modules... 玩玩而已可以不用才怪 囧>

  1. make menuconfig (記得拷貝舊的來用,在/boot/下面有)
  2. make all
  3. make moudule_install (用來做initrd.img) copy 檔案到系統/boot下,需要vmlinuz、initrd.img、System.map、新config
  4. 修改/boot/grub/menu.lst
  5. 重開機
確認一下

littleB:/home/bejo/code# uname -a
Linux littleB 2.6.32.4 #1 Fri Jan 22 07:00:51 CST 2010 i686 GNU/Linux
YES~

-----
總結來說,核心就是一個檔案,開機之後bootloader指到那邊去執行,initrd.img是為瞭解決巧妙的驅動問題,就是前人沒想到sata會出現嘛... 還是一個小小的kernel唷,bootloader之後就是交給initrd.img再交給vmliunz

檔案說明
System.map <--記得拷貝到 /boot/
What Is The System.map File?
There are 2 files that are used as a symbol table:
1. /proc/ksyms (在ubuntu 是 /proc/kallsyms,媽的~我開始覺得這東西流著debianㄧ樣GY的血液是真的)
2. System.map
這個檔案會紀錄module應該插入的symbol記憶體位置,如果模組有問題的話,可以確認一下。


vmlinux <-- 沒壓縮的核心檔
vmlinuz <-- 有壓縮的核心檔
bzImage <-- 有壓縮的核心檔,用bzip壓縮,把這個檔案拷貝到 /boot 下,然後更改成vmlinuxz
zImage <-- 有壓縮的核心檔,用gzip壓縮

.config <-- 系統原本的設定檔,如果要升級現有kernel可以在/boot 下面找到類似config-2.6.27-16-generic之前的前一份檔
所以可以把它拷貝出來餵給現在的核心吃,這樣就不會不知道選啥Kernel菜了,所以記得換過核心要順便把新的config塞進去,守規矩。

mkinitramfs 這東西製造出新的initrd.img
mkinitramfs -o initrd.img-版號 版號
(在這之前ㄧ定要make modules_install 因為它會吃/lib/module/板號)
(如果編譯端不是安裝端,可以用Makefile 改路徑騙過他)

修改開機的kernel選擇
/boot/grub/menu.lst
增加
title BeJo GNU/Linux, kernel 2.6.32.4
root (hd0,0)
kernel /boot/vmlinuz-2.6.32.4 root=/dev/hda1 ro
initrd /boot/initrd.img-2.6.32.4
savedefault



下面是Unbuntu的,有uuid跟debian不大ㄧ樣,照換也可以。
title linux kernel 2.6.27.7
uuid bdce929d-3c0b-4f10-aeb7-76b0fb8b62cd
kernel /vmlinuz-2.6.27.7 root=UUID=1d668bc0-d6b1-4798-8173-b05b65e925e7 ro quiet splash
initrd /initrd.img-2.6.27.7
quie

2010年1月21日 星期四

[語言] __FILE__, __LINE__

上次在神人那看到....他說:我就是要挺慣C,
恩...
可以交到這麼多正妹的慣C,我也很挺XD

看過
__FILE__, __LINE__ 沒?

C語言常常有那種知道的不要問,不知道的不要說的詭異(取自某討論區的黑暗氣氛...這根本是死結嘛)





其實這是GCC complier 預先就定義好的變數,不只這兩個,只要符合C99的標準有以下七個
__LlNE__
__FILE__
__FUNCTION__
__TIME__
__DATE__
__STDC__           (是否遵守ISO C )
__STDC_HOSTED__  (是不是HOST,非寄居)
__STDC_VERSION__ (版本)

用GCC的話並不完全符合上面的定義
__STDC_VERSION__ 就變成 __VERSION__
__func__ 等同於__FUNCTION__ 不過聽說GCC建議使用前者。

另外complier,我用GCC試過存在
__TIMESTAMP__

寫個程式印一下就知道了
printf("line: %d \n", __LINE__);
printf("file: %s \n", __FILE__);
printf("function: %s \n", __FUNCTION__);
printf("function: %s \n", __func__);
printf("time: %s \n", __TIME__);
printf("date: %s \n", __DATE__);
printf("STDC: %d \n", __STDC__);
printf("STDC_HOSTED: %d \n", __STDC_HOSTED__);
printf("VERSION: %s \n", __VERSION__);
printf("TIMESTAMP: %s \n", __TIMESTAMP__);


輸出:
line: 150
file: test.c
function: main
function: main
time: 15:13:28
date: Jan 21 2010
STDC: 1
STDC_HOSTED: 1
VERSION: 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
TIMESTAMP: Thu Jan 21 15:13:26 2010

這東西就可以視情況取用,很方便。
多方便?

例如我們要重新定義一個DBG()函數來幫忙debug好了

#define DBG(msg, arg...) printf("%s:%s(%d): " msg, __FILE__, __FUNCTION__, __LINE__, ##arg)

這樣我們就可以把DBG()當作printf()使用還多增加function name 行數等等可以查詢。


DBG("index:%d str = %s\n", index, str);
輸出: test.c:main(146): index:2147483647 str = bejo

--
那define 看起來十分詭異對吧 XD
其實那也只是置換的意思,把置換ㄧ下就很清楚了

DBG("index:%d str = %s\n", index, str);

被置換成

printf("%s%s(%d): " "index:%d str = %s\n", __FILE__, __FUNCTION__, __LINE__,  index, str);

DBG --> printf
msg --> "index:%d str = %s\n"
arg --> index, str

就ㄧ點都不奇怪了...

補充一下假指令#line 的用法
這用法可以在openl2tp這包open source看到,用在bison paswer相關

例如當
testA.c 是由bejo.c 自動產生時,run testA.c包好的檔案去debug會產生一些困擾,這時候我們可以這樣做

#line 888 "bejo.c"
        printf("%s line: %d\n", __FILE__, __LINE__);
        printf("line: %d\n", __LINE__);

輸出
bejo.c line:888
line:889

就會知道該去看該死的bejo.c 第888行

---
自動產生的code聽起好夢幻XD

2010年1月12日 星期二

[Ubuntu] SCIM - 輸入法

SCIM - 整合性的輸入法伺服 平常屋邦兔都是拿來工作,很少會打到中文,這次要裝上注音輸入法,哪有那種裝scim會動,裝gcin會動,等一下通通不會動這種鳥事阿,還真的有點稿死我 囧>

照慣例這是官網:
http://www.scim-im.org/

這篇是用SCIM的酷注音完成...... 很不順手 =___=
首先安裝好Ubuntu之後應該會有scim,但因為我是英文環境所以安裝上有點問題。

  • 確認language support 裝上中文包
  • 安裝scim- chewing
  • 需要一個工具:im-switch
          用來切換輸入法,尤其是在不同語系裡切換預設。

 執行
        im-switch -s scim
會發現
        Cannot find alternative `/e tc/X11/xinit/xinput.d/scim'
原因:
        scim沒有被加入到alternatives列表中
解法:
        update-alternatives --install /etc/X11/xinit/xinput.d/all_ALL xinput-all_ALL /etc/X11/xinit/xinput.d/scim 30

另外用im-switch -c 也可以用表單來切換輸入法。

#pkill scim
#scim -d
重新執行

不過..... 我還是登出登入才可以用,真他x的奇怪阿 囧>

ps. 新酷音還是很不順手...某後用