2015年5月2日 星期六

開機自動執行, boot script in Ubuntu

●Background:
=================================
1.)Ubuntu 14.04.2 LTS 64bit


●Procedure:
=================================
1.)Create Script File
e.g:
#!/bin/sh
your-command

2.) $ chmod 755 your-script-file
3.)Ubuntu tool bar -> Search Application: Startup Applications
4.)Add your-script-file
5.)Done


●Other Info:
=================================


●Comment:
=================================
有很多方法可以做boot script,但目前測試只有這個方法才能執行 xinput 的命令


●Refference:
=================================
[1]startup script for trackpad
http://ubuntuforums.org/showthread.php?t=1561311

修正GTP硬碟轉MBR仍不能裝雙系統Win7+Ubuntu問題

●Background:
=================================
1.)安裝雙系統:
Win7 64bit (先)
Ubuntu 14.04.2 LTS 64bit (後)
2.)說明:
GTP硬碟裝雙系統Win7+Ubuntu會有問題,首先要裝雙系統要把GTP硬碟格式轉成MBR,但若使用的工具不對,會殘留GTP table資料,雖然Win7能安裝,但在Ubuntu安裝時,仍會誤以為硬碟還是GTP格式,看不到Win7。
3.)注意事項:
 - 不要使用 Win7 的安裝光碟做 GTP 轉 MBR 的動作
 - 不要使用 Windows 的 "diskpart" tool 做 GTP 轉 MBR 的動作
 - 不要灌了 Win7 再操作以下步驟,以下步驟操作完後再開始灌雙系統
 - 灌好 Win7 後最好先裝顯卡driver,不然可能會在裝完Ubuntu後,無法進入Win7(預設的顯卡driver error)


●Procedure[1]:
=================================
1.)Launch Ubuntu 14.04 install DVD
2.)Select: "Try Ubuntu"
3.)Ctrl+Alt+T
4.) $ gdisk
說明:找不到tool的話請執行 $ sudo apt-get install gdis
5.) Key-in: /dev/sdX
說明: Device filename, X for a, b, c.... e.g.: /dev/sda 請注意要操作哪個硬碟!!
6.) Key-in: r
說明: Start recovery/transformation.
7.) Key-in: g
說明: Convert GPT to MBR.
8.) Key-in: p
說明: Preview the converted MBR partition table.
9.) Key-in: w
說明: Write changes to the disk.
10.)Done
說明: Key-in "exit" to exit gdisk. You can reboot now to install Win7 and do disk partition on Win7.


●Other Info:
=================================


●Comment:
=================================



●Refference:
=================================
[1]How to Convert a GPT disk layout to a MS-DOS/MBR layout without data loss
http://www.firewing1.com/blog/2012/03/05/how-convert-gpt-disk-layout-ms-dosmbr-layout-without-data-loss-and-gigabyte-hybrid

修正Ubuntu的vi不能進insert mode問題


●Background:
=================================
1.)修正vi不能進insert mode問題,Ubuntu的vi不完整[1]
2.)Ubuntu 14.04.2 LTS 64bit


●Procedure:
=================================
1.)Connect to internet
2.)Ctrl+Alt+T
3.) $ sudo apt-get install vim
4.)Done



●Other Info:
=================================
1.)使用此命令可以把vi comand導向vim: $ alias vi=vim
但在Ubuntu 14.04 不需要這麼打

2.)常用的vi指令:
不儲存並離開:
"ESC" -> ":" -> "q!" -> Press Enter
儲存並離開:
"ESC" -> ":" -> "wq" -> Press Enter


●Comment:
=================================
建議安裝ubuntu後馬上處理此問題,很多地方會用到vi


●Refference:
=================================
[1]LINUX,進入VI後為什麼不能切到插入模式
http://zhidao.baidu.com/question/147839980.html

更改 Grub 開機順序 與 倒數時間

●Background:
=================================
1.)更改 Grub 開機順序 與 倒數時間
2.)Ubuntu 14.04.2 LTS 64bit


●Procedure:
=================================
1.)Ctrl+Alt+T
2.) $ sudo gedit /etc/default/grub
說明:不要用vi,ubuntu的vi有問題,不能進insert mode
3.)Change "GRUB_DEFAULT" to 4
說明:Ubuntu是0,4是Win7,此值請看開機時的Grub menu,或去學著看/boot/grub/grub.cfg(麻煩)
4.)Change "GRUB_TIMEOUT" to 3
說明:修改Grub menu的倒數時間為3秒
5.) $ sudo update-grub
說明:產生新的config file,不要漏打了
6.)Done



●Other Info:
=================================


●Comment:
=================================
建議安裝ubuntu後馬上處理此問題


●Refference:
=================================

無法關閉touchpad (Ubuntu)

●Background:
=================================
1.)Ubuntu 無法偵測 touchpad,所以無法關閉 touchpad
2.)Ubuntu 14.04.2 LTS 64bit


●Procedure:
=================================
1.)Ctrl+Alt+T
2.) $ xinput list
說明: 找出touchpad的裝置與index,e.g.: PS/2 Generic Mouse,index = 13
3.) $ xinput -disable 13
4.)Done


●Other Info:
=================================
1.)打開裝置的命令為: $ xinput -enable 13
2.)以上命令關機後重置


●Comment:
=================================
1.)建議安裝ubuntu後馬上處理此問題,把以上步驟存成 boot script[2]
2.)但Index可能會變!!(如果有後來有新增鍵盤滑鼠類的週邊的話)


●Refference:
=================================
[1]How to disable the touchpad?
http://askubuntu.com/questions/65951/how-to-disable-the-touchpad

[2]開機自動執行, boot script in Ubuntu
http://fy123p.blogspot.tw/2015/05/boot-script-in-ubuntu.html

2015年4月24日 星期五

[C Language]關於指標、const、__in 、__out、IN、OUT

首先,*是指標,沒問題,但指標拿來當function argument(函式引數)時就會混淆了,好比說這個prototype:

int func(int *p);

請問它是:
1.將 *p 的值輸入給函式使用
2.還是把函式的運算結果放到 *p 中

看不出來! 有點經驗的人都知道程式是給未來的自己與其它人看的,增加可讀性的第一步是代碼,其次是註解,再來是文件;更有經驗的人會知道可讀性幾乎就等於開發效率。

基本上還有一個問題,那就是p可能是a pointer to int "array",而不是a pointer to int。

好,根據眾書本的說法,第一步是要好好取名字,例如:
int PrintAge(int *p);    //可以看出 *p 是用來輸入age,然後輸出(print)到console window
int GetAge(int *p);      //可以看出 *p "可能"是輸出age,因為也有可能從函式回傳值輸出,但已經明顯多了
int PrintAllAge(int *p); //由函式名可以推測 p 可能是a pointer to int array,因為看來會印出多個age

如果這個例子也對引數p好好命名,那會清晰更多;但內部要做什麼,仍然是毫無限制的,所以這時候const就很好用了。基本上,const有兩個功能:

1.在"宣告"變數時,將變數宣告成read-only的data
2.在修飾function argument型別時,限制function對此argument的權限為read-only
(不一定真的要傳read-only data進來,只是限制而已)

所以現在新的prototype就變成這樣了:
int PrintAge(const int *age);
int GetAge(int *result_age);
int PrintAllAge(const int *age_array);

明顯看出第1、3個函式引數是用來輸入的,第2個函式是用來輸出的。輸入/輸出是這麼重要,所以有不少的解法方案,好比說在名稱前面加上 in (e.g.: in_age),或是C++ complier內部用的empty define: __in __out [1][4][5]。

__in : 代表這個參數是input
__out : 代表這個參數是output
__in_opt : 代表這個參數是input,且可以選擇性(optional)輸入,通常選擇不輸入就是帶NULL pointer
__out_opt : 代表這個參數是output,且可以選擇性(optional)輸入,通常選擇不輸入就是帶NULL pointer

例子:
int GetAge(__out int *result_age);

由於 _ (underscore)開頭的東西,我們不要拿來用/也不要這麼命名[2],所以我們可以定義自己的用法,...或再看其它人是怎麼定義的,這時我發現UEFI的玩法還不錯,他們有定出這三個東西: IN OUT OPTIONAL,除了OPTIONAL太長,且放在參數的尾巴外,其它倒是可以學來在自己的程式上用,如:

#ifndef IN
#define IN
#endif
int PrintAge(IN  const int *age);

接下來看看一個較完整的範例:
int
SortIntArray (
IN OUT  int *array,
IN      const int array_length,
OUT OPT int *max_value_in_array,
OUT OPT int *min_value_in_array
)

OPT 就是 OPTIONAL 的意思。


最後再來個練習:
int func(int ***p);
請問這個函式是要對三維資料(注1)做操作,還是二維資料?

int func1(IN  int ***p);
int func2(OUT int ***p);
那這兩個呢?


答案是:
func1"很可能"是傳三維資料進去,func2"很可能"是傳二維資料出來,有IN OUT差很多,但!!這些還是會有問題,上面只是假設 *** 是多維的資料,但實際上有可能不是多維,就只是個 a pointer to a pointer to a pointer,雖然少見,但卻有它的用處,這就是虛擬記憶體、或記憶體管理等高等資料結構的設計。...其實怎樣都會有問題,所以就加上函式註解吧。

/*
    ***p is a "input" 3-dimentional data
*/
int func1(IN  int ***p);

/*
    ***p is a output pointer to a 2-dimentional data
*/
int func2(OUT int ***p);


最後,關於指標我非常建議去看參考資料[3]這篇文章,裡面精闢地闡述了:
1.Pointer: *
2.Constant: const
3.Reference: & (這裡是指C++的reference,而不是C的取址運算元,C++把&的用法擴充了)
4.Array: []
5.Function pointer: (*)()
對於複雜指標的用法,裡面也提供了可讀性最高的方案: 多用typedef。


結論:
1.命名,還是命名
2.函式引數能用const就用const,這是唯一能規範實作的方法
3.用 IN OUT OPT 來做進一步的提示
4.對多維資料/指標特地加上注解,至少要標出幾維


注1:
精確點來講,***是三維資料,不是三維陣列,陣列是指所有的資料都是"連續"的,而***概念類似陣列,但資料是不連續的(陣列的維合),好處是彈性,但接受這筆資料的人要知道內部各維資料的陣列長度。





參考資料
====================================================================
[1]stackoverflow: Meaning of __in , __out, __in_opt
http://stackoverflow.com/questions/9834550/meaning-of-in-out-in-opt

[2]PTT看板C_and_CPP: Re: [問題] 絕不使用單一底線開頭的名稱
https://www.ptt.cc/bbs/C_and_CPP/M.1320472279.A.C06.html

[3]Codeproject: How to interpret complex C/C++ declarations
http://www.codeproject.com/Articles/7042/How-to-interpret-complex-C-C-declarations

[4]stackoverflow: Empty define in C
http://stackoverflow.com/questions/13892191/empty-define-in-c

[5]stackoverflow: C++: Empty function macros
http://stackoverflow.com/questions/9187628/c-empty-function-macros