Ming's blog

一個軟體工程師的旅程 :)

※ 這篇有點年代了,寫作風格有點鬆散,文章內有不少與問題無關緊要的故事,急著解決問題的話,可以先參考以下幾篇:

Linux系统启动故障总结:单用户模式/GRUB引导故障/Linux救援模式
Win7 + Linux Mint 14.1 雙系統安裝實錄
Boot-Repair
使用ubuntuliveCD重新安裝grub2
GRUB使用说明及Linux和Windows双系统Grub丢失恢复和linux硬盘安装方法
Linux Mint Rebuild MBR/LVM Boot Repair

Good luck!

前言:禮拜五難得沒熬夜(其實是太累攤下去就沒起來了),禮拜六早晨很正常的七點左右起床,刷牙洗臉之前先把身旁的筆電打開,接著進入Windows XP準備一天的開始,卻看到罕見的錯誤訊息,詳細已經忘記了,不過中文相關資料不多,英文相關資料也不多,解決方式嘗試之後,搬出了系統還原,結果不還原還好一還原就近不去系統了。

連假,算了,決定來重裝系統,禮拜六先花了半天的時間製作Ming XP,經過無數次的測試,版本號從Ming XP1.1 > 1.3 > 1.5 > 1.6 > 跳至1.7終於完成理想的系統(沒錯也在VMWare中重裝了四五次),裝完系統之後開機,該死,MBR果然被Windows洗掉了,看來還原系統環境之前得先折騰選單了,Ubuntu之前更新完也被洗掉過一次,雖然估計得花點時間,不過應該是不會太久才是。

大致想了一下解決方案,參考網路上很多文章,最後都是無解,禮拜六忙到了凌晨三四點,早上睡到十點起來決定先把XP環境還原好,XP環境還原好差不多要回鄉下了,這次跟自己說好不帶筆電回鄉下加上昨天折騰整個晚上都沒結果,MBR被覆蓋的問題決定等到228回來臺北在說。

假期很快過去,中午回到了濕冷的臺北,當然沒忘記GRUB選單被覆蓋掉的問題,(經過五小時,過程略,在229這個四年一次的日子開始的五分鐘內,我終於搞定這個問題了)

正文開始:

首先,記得將開機磁區改為Linux所在區,這是回鄉下的第一個突破口,可是之後又卡住了,接下來參考網路上的方法:

(以下操作在Fedora 15 LXDE Live CD指令環境完成)

su
mount /dev/sda3 /mnt
grub-install /dev/sda3 // (沒錯,不需要chroot)

接下來開機看到grub>_的畫面,又卡住了,接下來嘗試看看

find /boot/grub/stage1

原本其實找不到stage1的,鍵入之後竟然給我了(hd0,2)

接著root過去,然後setup (hd0)

竟然成功通過檢查得到done~

重新開機想說應該成功了,結果又看到grub>_

再查了一些資料回到Fedora Live CD 打開命令提示字元,無論如何都洗不掉MBR,還是沒有收穫。

http://www.path8.net/tn/archives/2027
http://kenshinnn.blogspot.tw/2009/03/linuxmbr.html

參照網路文章進入了Debian,興喜若狂的輸入update-grub,成功,shutdown -r now,又是那個grub>_的畫面,又在一次進入Debian,想了很久決定把MBR先洗掉在寫入

本來打算拿出Spfdisk(一直很不願意用,有慘痛經驗),最後決定找在Linux下重寫MBR的方式,dd指令祭出之後,grub-install + update-grub 雙管齊下(不確定哪個導致成功),開機終於看到了GRUB畫面。

認識 srand() / rand() 算蠻長的時間了,寫過 C/C++ 的人都知道,他們是 標準 C/C++ 用於產生亂數的函數組合。Ming 這次負責迎新活動上面一個小程式,這個小程式用於將各班級不對齊的人數,自動計算並分配成 n 組(實際上就是做直屬分配 / 共 n 人 j 人一組以某班人數 p 為基準共 n 組)。

迎新活動結束後,無聊又拿程式起來 run run 看,赫然發現一件奇怪的事情,有某個學長連續好幾次的結果都跟 Ming 同組(如果是學妹我可能就沒動力修了),再看看其它人也有這個狀況,一二年級會變動可是 二、三 年級結果都是相似的,慘了有 bug … 。

有 bug 要修阿,原先以為是我分配邏輯寫錯(首次使用不熟的 2d vector),查了分配部分的程式碼找了許久還是找不到問題點,結果又把程式 run 了幾次,發現有幾次結果是會改變的,接著我就開始懷疑是不是 srand() / rand() 有問題。

簡單提一下我對直屬分配程式的作法是這樣:

example.Cpp
1
2
3
4
5
6
7
8
9
10

// STL 容器
vector<vector<wstring> > classVector;

// handleVector() 負責處理 各班人員姓名讀入 / classVector 賦值 / 亂數排序(關鍵 - srand() 寫在 handleVector() 中)
handleVector(fileNameOne,classVector,1);
handleVector(fileNameTwo,classVector,2);
handleVector(fileNameThree,classVector,3);
handleVector(fileNameFour,classVector,4);

我懷疑是函數執行間隔速度過短,間接導致 srand((unsigned int)time(NULL)); 中的 time() 函數抓到的時間是幾乎沒有差異性的(每次傳入的 seed 一樣的話,會導致亂數結果相同)。

我初步的處理方式是在 handleVector() 中加入 Sleep(1000),讓每次執行函數時延遲 1 秒鐘的時間,重新執行程式後,輸出結果前會先延遲四秒鐘左右Sleep(1000) * 4。

不過大致上得到的結果是正確的 -> 每次的結果都是散的(正確)。

興高采烈的以為修好 bug 之後,跟老師討論了這個結果,結果老師說 srand 的 seed 用 time() 是不適合的做法,回去問了一下資深的網友,他說傳 time() 沒有問題,問我是不是重複 srand() 了 … 這句話有點當頭棒喝的感覺。

handleVector 執行了四次 …,srand() 也重覆跑了四次,也就是說當這四次函數執行時間非常非常短的時候,傳入的 seed 是一樣的。(A秒執行 time() 跟 A秒執行 time() 會讓 time() == time(),也就是說傳入的 seed == seed,導致每次 rand() 結果都是一樣的)

把 srand() 搬到 main() 程式入口點中,程式果然正常了,而且又沒有 Sleep(1000) 延遲四秒鐘才輸出的問題。

只知其然,而不知其所以然 不太好,要了解 srand() 的原理,最快的方法當然是直接看內部實現的代碼了(標準 C++ 的優點之一)。

首先看一下 srand() 的代碼:

srand
1
2
3
4
5
6

void __cdecl srand (unsigned int seed)
{
_getptd()->_holdrand = (unsigned long)seed;
}

srand 傳入一個 seed (例如我們傳入 time() 返回值), _getptd()->_holdrand 將 seed 存到 _holdrand 變數,初始化完成。

接下來看一下 rand() 的代碼:

rand
1
2
3
4
5
6
7

int __cdecl rand (void)
{
_ptiddata ptd = _getptd();
return( ((ptd->_holdrand = ptd->_holdrand * 214013L + 2531011L) » 16) & 0x7fff );
}

呼叫 rand() 後,會對 _holdrand 變數(存 seed) 做 (((_holdrand * 214013L + 2531011L) » 16) & 0x7fff) 操作,並將這個操作後的值返回,且將這個新的值覆蓋原本的 _holdrand 變數。

一直不理解 rand() 為何被稱作”偽亂數”的原因(之前有測試過,rand() 得出的結果蠻平均的),看完這兩段應該有豁然開朗的感覺,也就是說其實所謂的 rand() 是透過人為的算法去操控的,並非實際意義上的 “亂數”,不過 rand() 得到的值還算穩定,作為小程式開發還算堪用,

也就是說,如果像我一樣一直 srand ,就會讓 _holdrand 一直被刷新,而當 time() == time() 的時候,會導致下一次 rand() 做 (((_holdrand * 214013L + 2531011L) » 16) & 0x7fff) 操作時,得到一樣的結果。

他的過程有點像是根據傳入的 seed 產生一個無窮大的序列,每次 rand() 就會從中取一個數字出來(當然這個序列實際上是不存在的,便於理解),而上面兩行程式碼就是產生這個序列的作用程式碼,透過原始數字 A 做第一次計算,後面不斷利用這個數字做一定的運算,得到 A2 A3,由於每次計算後的值都會不同,所以可以保持 rand() 的品質。

重複 srand() 或者 srand(常數) 都會導致這個不斷透過固定計算生成的虛擬序列,變成同一個序列。

例如: A 的內部實現是 a*a 那我連續傳入 A(1) A(1) A(1) 都會得到一樣的結果(rand 的計算方式有異曲同工,也是透過實際運算得出後面的數字,所以稱為偽亂數)。

結論:

這次歸根究底其實是自己對於 srand()/rand() 實際原理沒有實際掌握的原因,才犯了重複 set seed 這種低級的錯誤 …。

經過這次 bug,有更深的體會應該要更加關注程式的細節、隨手可得的原始碼(如果看得懂的話,可以便於了解內部實現)。

一次深刻的經驗,了解程式 bug 的影響,這次幸好問題是發生在學校的小 program,出包最多就是修正問題、重新分配一次,如果是實際專案,出包的話影響的是實際的公平性(有違亂數分配程式的初衷),那可能接下來就是收到一大堆客訴電話、信函了 …。

P.s. 羨慕 Logdown 的 Markdown 編輯器(昨天文章寫到一半電腦放著去上學,結果回來自己莫名關機了,還有 restore 可以按,超溫馨.__.),Tumblr 一直沒在 Markdown 編輯器下功夫阿 …(有一些很奇怪的解析問題 …)。

今天想要找點英文資料,輸入一個關鍵字出來都是”中文”,bing 好像又找不太到,所以就決定去 google.us 了,結果發現無論是輸入:google.com 或者 google.us 都會被重定向到 google.com.tw,找了一下資料之後發現可以透過:

https://www.google.com/webhp?hl=*language*

language 將替換成適當的 Language Code

w3schools.com 上面有一份 Language Codes 可以作為參考

HTML ISO Language Code Reference

最近覺得需要一款功能較為豐富、詳細的 Task Manager,最後選擇免費、開源的「Process Hacker 2」,Windows 老使用者在開管理員無外乎就是直接在工作列上「右鍵→啟動工作管理員」、「Ctrl+Shift+ESC(Windows 7改成這樣真的有夠難按)」,如果要啟動工作管理員還要跑到資料夾中去點,感覺有點麻煩,所以就找了一下資料,將系統預設 工作管理員 為 Process Hacker、Process Explorer … 等等第三方工作管理員。

  1. 首先打開 regedit
  2. 找到 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\taskmgr.exe]
  3. 右鍵→新增→「字串值」
  4. 名稱「Debugger」
  5. 數值資料(第三方工作管理員路徑) 例如:「D:\Windows\PF\ProcessHacker\ProcessHacker.exe」

關閉 regedit 之後,在試著用習慣的方式進入預設工作管理員,就會發現預設打開的是第三方的工作管理員了!

最近缺幾個 Icon 給 仿dock 使用,所以用 Photoshop 隨便打幾個字弄了一個出來(典型殺雞用牛刀),想按另存新檔匯出的時候卻遲遲不跳出令存新檔視窗,試了一下還是無法讓他匯出,上網查了一下發現是解析度的問題,Photoshop 在小於 1024*768 的解析度底下,是跑不出另存新檔視窗的(可以儲存 .psd 但不能存其它格式)。

02.png

知道原因出在哪裡後,趕緊去調整螢幕解析度,結果發現 Ming 這臺 Netbook 最高的解析度就是 1024*600(囧…),找了一些選項還是無法修改,最後只好上網找資料,很自然的輸入「虛擬解析度」這個關鍵字,拜 Netbook(小筆電) 風行一段時間所賜(加上許多人還捨不得讓他退役),遇到相關問題的網友還挺多的,最後終於找到一篇有用的解法…

開啟虛擬解析度

  1. 打開 regedit (註冊表編輯器)
  2. 編輯(E)→尋找(F)
  3. 尋找目標:display1_downscalingsupported
  4. Enter
  5. 將值由 0 改為 1
  6. 重新開機

01.png

重開機後,到 螢幕解析度 調整的地方:

03.png

good job!,試一下 Photoshop 也可以正常另存圖片,當然畫面是強行模擬的,當然不可能有原始 1024*768 的清晰,使用完畢之後就趕緊調整回來了。

最近比較多遇到這個問題的大概就是 Windows 8 Modern UI(Metro) 無法順利使用。

Q&A

Q:找不到 display1_downscalingsupported 註冊表鍵值

有些顯示卡不支援此參數。可以考慮 虛擬桌面 軟體的方案,虛擬桌面軟體大都有 虛擬解析度 的功能,不過如果是為了使用 Windows 8 Modern UI 那虛擬桌面大概也無解了,請節哀 … (或者可以試試看網路上提供的一些 虛擬解析度 軟體,沒使用過就不多做介紹)

Q:此解決方案適用於?

Windows XP/Vista/7/8 都可以試試看(原先找到的介紹頁面是 work 在 Windows 8 底下,而 Ming 在 Windows 7 底下也找的到),故可以猜測這個註冊表鍵值應該不是系統原生鍵值,而是因各家顯示卡驅動而異。

reference

最近把慣用的 Linux-based 系統從 Ubuntu 換成 LinuxMint 了,LinuxMint 算是最近蠻火紅的 Linux-based,訴求主要還是面向一般使用者,安裝 LinuxMint 13 KDE(Maya;Long Term Support) 後,發現竟然沒有內建中文輸入法,於是只好自己動手安裝了。

Install

安裝過程仰賴 Terminal。

Step 1

取得 root 權限

sudo -i -H

Step 2

匯入金鑰

sudo apt-key adv —keyserver keyserver.ubuntu.com —recv-keys 835AB0E3

Step 3

加入更新源

echo “deb http://cle.linux.org.tw/gcin/download/debian eliu release” » /etc/apt/sources.list

或者(上下擇一即可),利用 vim(或者 vi) 手動加入一行

vim /etc/apt/sources.list 加入:deb http://cle.linux.org.tw/gcin/download/debian eliu release

Step 4

更新源並安裝 gcin

sudo apt-get update sudo apt-get install gcin

Finish!

今天在 Konsole 中使用 apt-get update 指令,結果一直返回錯誤結果,仔細看了一下錯誤提示,顯示無法取得某個後來加入的 ppa 源。

W: 無法取得 http://ppa.launchpad.net/blueman/ppa/ubuntu/dists/precise/main/source/Sources,404 Not Found
W: 無法取得 http://ppa.launchpad.net/blueman/ppa/ubuntu/dists/precise/main/binary-i386/Packages,404 Not Found
錯誤 http://ppa.launchpad.netprecise/mainSources 404 Not Found
錯誤 http://ppa.launchpad.net precise/main i386 Packages 404 Not Found

解決方法

上網找了一下,問題很快就有解答了,原因應該是出自該 ppa 源被砍檔,所以會報錯。

只要把該報錯的 ppa 源刪除即可,作法也不難,所有 ppa 源都會在 /etc/apt/sources.list.d/ 這個路徑下面

sudo cd /etc/apt/sources.list.d/
ls
rm -i ppaname.list ppaname.list.save
rm:是否移除普通檔案‘blueman-ppa-precise.list’? y
rm:是否移除普通檔案‘blueman-ppa-precise.list.save’? y
apt-get update

reference

MP(Apache + MySQL + PHP) 環境,原本首選是Drupal 社群的 TWAMP 麻瓜架站包(也用好幾年了),不過在 Windows 7 環境有點不如意,所以輾轉找其它解決方案,最後決定使用 XAMPP。

之前在租屋處有設置過一次,不過隔了一些時間想要在家裡電腦也佈署一下發現好像細節都忘記了,決定寫篇文章把要調整的一些小地方筆記一下。

  • Name:XAMPP
  • Web Links:http://www.apachefriends.org/
  • About:XAMPP是一個把Apache網頁伺服器與PHP、Perl及MySQL集合在一起的安裝包,允許用戶可以在自己的電腦上輕易的建立網頁伺服器。
  • Download:《link》

銘使用 XAMPP for Windows Portable(v1.8.1),並在 Windows XP SP3 運行。

Setup

  1. Portable 版本下載後解壓縮到本地端。(任意:\xampp)
  2. 執行 :\xampp\ 目錄底下的 setup_xampp.bat
  3. 執行 xampp-control.exe
  4. Start Apache、Mysql 兩個 Moduble,Status change detected: running 出現且 Module 轉成綠色底色代表 start 成功。[1]
  5. 進入 http://localhost/xampp/index.php 並 選擇語系。
  6. 成功進入後臺。

  1. 出現 Error: Apache shutdown unexpectedly. 可能的情況是:1. XAMPP 位於多層目錄之下,且未執行 setup_xampp.bat 2. 端口遭到占用,可以使用 netstat -nao(or:netstat -nao | find “0.0.0.0:XX”) 並且配合 tasklist /fi “pid eq PID” 找出占用端口並 kill。

Security

開心地安裝完之後,可以開始檢視 XAMPP 後臺提供的各項參數,在左邊頁面中可以看到 Security(安全) 項目,點進去後會發現預設設定的 XAMPP 三項安全檢查都是呈現 不安全 的紅字,XAMPP 預設沒有針對 XAMPP 後臺、Mysql、phpmyadmin 設置密碼,為了安全考量建議設置上密碼。

要設置 XAMP P 後臺(.htaccess 目錄保護)、Mysql、phpmyadmin 請連結至:[http://localhost/security/xamppsecurity.php]http://localhost/security/xamppsecurity.php 可以針對這些項目做設定。[1]


  1. 勾選 Safe plain password in text file? 選項,會將設定的密碼明文存放至 xampp\security\xamppdirpasswd.txt / mysqlrootpasswd.txt 中

Remark

  1. 網頁檔案置於 xampp\htdocs 目錄中。
  2. phpmyadmin 地址:http://localhost/phpmyadmin/
  3. bin 目錄位於 xampp\mysql\bin (存放 mysql.exe 等等文件)。

Reference

關於 C/C++ 入口函數 main() 的參數,「int argc / char **argv」,銘看過的入門書剛開始都選擇跳過解釋這兩個參數,個人猜測是因為還沒有講到 function 概念,所以沒有講,今天看 Windows API 的 example 的時候,發現書上的 example 使用了很大量的 int argc / char **argv,當時在火車上其實我有點納悶這兩個參數,我知道這是一些 IDE 會自行加入的參數,不過沒有太多印象,手邊也沒有網路,只能透過 example 大概知道是再命令列中的附加參數讀取。

到了租屋處後,找了一下資料,初步了解 argc / argv 兩個參數的用途,簡單的說就是可以在外部命令列中加入附加的參數,並且透由 argc / argv 協作讀取使用者填寫的參數。

  • int argc // 附加參數數量(同時也是 argv 的大小)

例如有一個程式 shutdown.exe,我在命令列中輸入:

  • shutdown.exe -r -t 0

argc 的值會是:4

  • char **argv(char ^argv) // 紀錄各個參數。

argv 的大小 = 使用者輸入的參數數目大小。

可以透過:

  • argv[i]

方式讀入命令列輸入的參數,延續上面的例子

example.cpp
1
2
3
4
5
6

cout « argv[0]; // 輸出:shutdown.exe
cout « argv[1]; // 輸出:-r
cout « argv[2]; // 輸出:-t
cout « argv[3]; // 輸出:-0

如果要讀取使用者所有輸入的參數可以:

example.cpp
1
2
3
4
5
6

for(int i = 0;i < argc;i++)
{
cout « argv[i] « endl;
}

即可讀到命令列所送進的所有參數。

reference

0%