2009年7月7日 星期二

取得LINUX系統記憶體剩餘空間

在linux下,沒用到的記憶體空間會被拿來當作buffer/cache使用,

以加速I/O存取

所以會感覺記憶體占用很多,

其實實際上如果程式需要記憶體,

就會釋放buffer/cache的空間,所以通常記憶體幾乎都是保持在很高的使用量。



使用free指令,

"-/+ buffers/cache"那一行的free就是實際上系統剩下來沒被其他程式吃掉的記憶體大小


可以用以下的指令取得真實的剩餘空間
echo -n free memory:;free -m | grep buffers/cache | awk '{print $4}'

2009年7月6日 星期一

C陣列與指標

宣告陣列時,
無論是幾維的陣列,
C語言都以分配一塊連續的記憶體空間來處理。


所以這種時候,可以把它當一維陣列處理

C以row為主,假設是二維陣列 arr[2][2]
當一維時的順序就是:
arr[0][0] arr[0][1] arr[1][0] arr[1][1]




雖然指標和陣列用起來差不多,
不過實際上意義是不太一樣的,
可以參考
http://dascan.pixnet.net/blog/post/15600458
http://squall.cs.ntou.edu.tw/cprog/Materials/AdvancedArray.html





要宣告一個指標代表陣列,要用以下的方法:

int data[5][5][5][5];
int (*p)[5][5][5];

可以參考
http://blog.udn.com/cchahacaptain/2197712

2009年7月2日 星期四

混合C與C++的程式

參考這個網站的:
http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html

在c++的程式內,使用C++標準函式庫,需要標明namespace:
#include <>; //cstdio

int main(){
...
std::printf(...);
...
}

在c++的程式內,使用C標準函式庫,用法跟c一樣:
#include <> //stdio.h

int main(){
...
printf(...);
...
}

在c++的程式內,使用C函式庫:
extern "C" {
#include "" //my-header.h
}

int main(){
...
my_func(...);
...
}


若要同一個header file給c與c++直接使用,也可以在header內加上exter "C",並判斷目前是c或c++使用

------------------------------
//my-header.h
#ifdef __cplusplus
extern "C" {
#endif

my-function(...);

#ifdef __cplusplus
}
#endif

------------------------------
//main.cpp

#include "" //my-header.h

int main(){
...
my_func(...);
...
}
------------------------------

若不想要include my-header.h,只要使用某幾個c function,可以直接宣告完整的prototype
//main.cpp
extern "C" my_func(int a, int b, int c);
or
//main.cpp
extern "C" {
my_func1(int a, int b, int c);
my_func2(int a, int b, int c);
my_func3(int a, int b, int c);
}
用到時直接用
//main.cpp
my_func1(...);

若要讓c程式call到c的某個function, 使用extern "C"可以使complier將此function給linker的資訊使用c的格式

//my.cpp
extern "C" my_cpp_func(int a, int b);

my_cpp_func(int a, int b){
...
}




2009年6月28日 星期日

取得浮點數(float)的最大值

其他資料型態應該也可以這樣做...
因為不同平台的資料型態的位元數可能不太一樣,用這個方法比較保險

  1. include float.h
  2. use FLT_MAX

2009年6月27日 星期六

計算程式碼行數

wc -l *.c *.h | grep total

wc: 計算行數、字數及字元數
  • -l 計算行數(line)
  • -w 計算字數(word)
  • -c 計算字元數(character)

2009年6月25日 星期四

C陣列長度取得(用malloc的方法)

當使用動態記憶體配置時

無法使用sizeof的技巧來取得陣列長度

不過可以寫一個自己的malloc和free來計算並維護各個動態分配的長度!!


  1. 寫mymalloc在malloc時記錄下這塊記憶體的陣列元素個數
  2. 寫myfree在free時把記錄下來的對應刪掉

#include
#include
#include

typedef struct arr_sz_t{

void * pointer;
int length;

struct arr_sz_t *next;

}arr_sz;

static arr_sz *sz_mapping;

void* mymalloc(int length, int size);
void myfree(void *p);
void add_sz_entry(void* p, int length);
int arr_length(void* p);

//input 1.array length 2.unit size
void* mymalloc(int length, int size){


void* ret = malloc(length*size);

add_sz_entry(ret, length);

return ret;
}

//free with mapping table
void myfree(void *p){

free(p);

if(sz_mapping != NULL){
arr_sz * t;
t = sz_mapping;

if(t->pointer == p){
sz_mapping = t->next;
free(t);
return;
}

while(t->next != NULL){
arr_sz *next;
next = t->next;
if(next->pointer == p){
t->next = next->next;
free(next);
return;
}

t = t->next;
}
}

}

void add_sz_entry(void* p, int length){
arr_sz* t = (arr_sz *)malloc(sizeof(arr_sz));

t->next = NULL;
t->pointer = p;
t->length = length;

//no sz_mapping
if(sz_mapping == NULL){
sz_mapping = t;
}
//insert
else{
t->next = sz_mapping;
sz_mapping = t;
}
}



//if no mach in mapping table, size is 0
int arr_length(void* p){
//no mapping data
if(sz_mapping == NULL){
return 0;
}

arr_sz* t;
t = sz_mapping;

while(t != NULL){
if(t->pointer == p){
return t->length;
}
t = t->next;
}

return 0;
}


int main(void){
srand(time(0));

int *data[50];

int i;

for(i=0;i<50;i++){
data[i] = (int *)mymalloc(random()%50, sizeof(int));
printf("size of data[%d]: %d\n", i, arr_length(data[i]));
myfree(data[i]);
}

return 0;

}

2009年5月19日 星期二

C的typedef

typedef的功用就是把某些東西變成一個預設的型態(像是int、double、char等型態)來使用
這些東西可以是enum、struct...


  • 原本:
struct people{
char name[20];
int height;
int weight;
};

struct people a;

  • 可以寫成
typedef struct people{
char name[20];
int height;
int weight;
}People;

People a;


  • 原本
enum week{ Sun, Mon, Tue, Wed, Thu, Fri, Sat};
enum week today = Sun;
  • 可以寫成
typedef enum week{ Sun, Mon, Tue, Wed, Thu, Fri, Sat}Week;
Week today = Sun

C的enum

實際上enum應該裡面是int,
可以用printf的%d來顯示,
預設的對應就是從數字0開始,
例如enum week{ Sun, Mon, Tue, Wed, Thu, Fri, Sat};
Sun = 0, Mon = 1, Tue = 2, Wed = 3..........................

當然這個對應可以手動指定,像是這樣:
enum week{ Sun=1, Mon, Tue, Wed, Thu, Fri, Sat};
手動指定之後後面若沒有手動指定則會依照手動指定的那一個一直遞增。
Sun = 1, Mon = 2, Tue = 3, Wed = 4.............

要注意有時候手動指定可能會有問題,像是這樣:
enum week{ Sun, Mon, Tue=1, Wed, Thu, Fri, Sat};
Sun = 0, Mon = 1, Tue = 1, Wed = 2.............


====================================================================
  • 一般用法,宣告一個叫做week的列舉,宣告一個week型態的today且指明是哪一天
enum week{ Sun, Mon, Tue, Wed, Thu, Fri, Sat};
enum week today = Sun;

  • 在宣告week時可以順便宣告這種型態的變數today
enum week{ Sun, Mon, Tue, Wed, Thu, Fri, Sat}today;
today = Sun;

  • 可以使用typedef把enum week定義成Week型態,之後就直接使用Week型態來宣告變數即可,不必每次都再加入enum(簡單來說就是之後都用Week取代enum week)
typedef enum week{ Sun, Mon, Tue, Wed, Thu, Fri, Sat}Week;
Week today = Sun

2009年5月5日 星期二

ubuntu內的sh是指到dash

bin/
lrwxrwxrwx 1 root root 4 Dec 6 16:29 sh -> dash

dash使用for(( i=0;i<10;i++> ))這種用法會出現
Syntax error: Bad for loop variable




解決方法是:
  1. 使用bash來跑script
    bash a.sh
  2. 修改~/.bashrc加入
    alias sh='bash'



ps. 使用dash的原因
sudo dpkg-reconfigure dash

The default /bin/sh shell on Debian and Debian-based systems is bash.
However, since the default shell is required to be POSIX-compliant, any shell that conforms to POSIX, such as dash, can serve as /bin/sh.
You may wish to do this because dash is faster and smaller than bash.


2009年4月29日 星期三

FTL介紹

FTL(flash translation layer)是一個轉換的介面,
使得flash 能夠被當作一般的儲存裝置使用(因為他不能直接更新檔案內容)

主要的作用有:
  • 位址轉換,把LBA(logical block address)轉換成flash上的位址
  • garbage collection(GC),由於flash的out-of-place update的關係,會造成有一些page被invalid掉,所以需要回收這些page
(FTL的效能受GC影響最明顯)






上面的page 和block大小只是個範例,實際上有的會不一樣(例如page為4K之類)



FTL位址轉換對應基本上最簡單的可以分成兩種:
  • page level - 對應比較細,但占用較大的轉換表(非常之大......)
  • block level - 對應比較粗躁,在GC的overhead很大(因為只要修改一個page就要重寫整個block),但是節省轉換表
基本上page level是沒辦法用的,block level有缺點,所以有一些替代方案,
像是已知的NFTL或是Log buffer-based FTL schemes之類

2009年4月23日 星期四

linux share memory用法

http://www.ecst.csuchico.edu/~beej/guide/ipc/shmem.html

可以用man 2 shmget查詢相關資料

需要include
sys/shm.h




主要有四個function:
  • shmget() - 建立共享記憶體
  • shmat() - attach 共享記憶體
  • shmdt() - detach 共享記憶體
  • shmctl() - 設定共享記憶體

int shmget(key_t key, size_t size, int shmflg);
  • key可以這樣用:(key_t)1234
  • size:以byte為單位的大小
  • shmflag:
    IPC_CREATE | 0666
    (0666是權限)
  • 若shmflag內有IPC_EXCL 則表示:
    若之前用同一個key建立過share memory,則此次建立會失敗(防止用到已創立過的)
    若沒用這flag就會連接到同一個地方
  • 回傳值是shmid,錯誤時則會回傳-1
void *shmat(int shmid, const void *shmaddr, int shmflg);
  • attach會把個shmid的share memory的位址放到shmaddr
  • 若失敗則shmaddr為-1
int shmdt(const void *shmaddr);
  • detach

若要移除已經建立的share memory,須使用shmctl:
先拿到shmid之後,用shmctl即可移除
shmctl(shmid,IPC_RMID,0);




寫出我的簡單範例做講解...







#include
#include

int main(int argc, char* argv[]){

int data[100];

int shmid;
void *shared_memory = (void *)0;

shmid =
shmget ((key_t) 123, sizeof (int) * 100, 0666 | IPC_CREAT);

if (shmid == -1)
{
fprintf (stderr, "shmget failed\n");
exit (1);
}

shared_memory = shmat (shmid, (void *)0, 0);

if (shared_memory == (void *)-1)
{
fprintf (stderr, "shmat failed\n");
exit (1);
}
printf ("Memory attached at %X\n", shared_memory);

if(argc == 2 && strcmp(argv[1], "-d") == 0){
printf("reset data to 0!\n");
((int *)shared_memory)[0] = 0;
}

printf("old data:%d\n", ((int *)shared_memory)[0]++);


printf("new data:%d\n", ((int *)shared_memory)[0]);

exit(0);
}

SKYARTEC 七動遙控器DIP開關修復

這台是買二手的,

遙控器上面控制陀螺儀感度是否可調整的DIP開關接觸不良,

要按著才能調整,很麻煩!


不過想到換DIP一次要解焊24跟針腳就覺得麻煩,

後來就直接就壞掉的那個開關接腳接到另外一個開關上面。






電鑽改裝鋰電

家樂福牌12V電鑽,雖然力道還算不錯(轉速有點慢)

但由於使用的鎳鎘電池不好,一下下就沒電了...

改裝成18650(3S1p 有分壓充) 以我的情況大約用兩三個禮拜才需要充一次。








自製直升機尾支撐架

由於不小心把尾翼摔裂了,

尾旋翼打到地上,

培林也打壞了...

所以就裝上碳纖棒代替,

相較之下碳纖棒比本來的尾翼堅固許多









詳細作法是用電木切掉一個長條行的缺口放置碳纖棒,

再把這組東西鎖在尾翼和尾齒輪箱的中間,

最後再用漆包線固定碳纖棒。




====================================================


由於原本的尾翼垂直的不好看

所以把它改成斜的...











2009年2月24日 星期二

期刊的排名

查詢各期刊的排名


ubuntu style kernel install

1.install:
build-essential
make-kernels
libncurse

linux-header
linux-source

2.make menuconfig

3.make-kpkg clean

4.make-kpkg --initrd kernel_image kernel_headers

5.sudo dpkg -i linux-image-<source version>_<source
version>-10.00.Custom_i386.deb linux-headers-<source version>_<source
version>-10.00.Custom_i386.deb

2009年1月21日 星期三

Fwd: linux核心編譯,增加新核心

詳情參考鳥哥
http://linux.vbird.org/linux_basic/0540kernel.php


1.取得原始碼
kernel.org

2.設定
$ make menuconfig
最好載入目前設定(/boot/config......)再修改

3.編譯
$ make

4.安裝模組
$ make modules_install
會安裝到/lib/modules/核心版本/
(所以如果編跟本來同版本的話會用到同一個資料夾 最好備份原來的)

5.核心檔案放在:
原始碼/arch/i386/boot/bzImage
複製到/boot/內以供開機使用
檔名最好改成"vmlinux_核心版本"以供辨認

6.建立initrd(Initial RAM Disk)
initrd 可以將 /lib/modules/.... 內的『開機過程當中一定需要的模組』包成一個檔案
確保可以順利掛載root,這樣其他的module就可以在/lib/modules/裡找到了
$ mkinitrd initrd_`uname -r` `uname -r`
會產生檔名為initrd_`uname -r`.EL的檔案
(不一定要`uname -r`,自己取名,因為通常要做的版本跟自己現在用的不一樣)

7.複製system.map
$ cp 原始碼/System.map /boot/System.map.版本號
這樣才不會稿混

8.修改grub
$ vi /boot/grub/menu.lst
複製一份本來可以用的
然後改一下設定
把initrd和kernel的檔案改成新編好的

9.reboot & try it