gdb
生成core文件的條件
-g // gcc -g main.c -o exe
ulimit -c 1024 // ulimit -a
權限問題:exe文件的擁有者,否則可能不能生成core文件。 // 用root, 不用sudo。sudo沒有打印“core dumped"
core文件的相關信息
默認位置:同exe文件的位置,若程序中有chdir(),則有可能改變。
默認名字:core
可以通過 /proc/sys/kernel/core*,等配置文件修改 // echo 1 > core_uses_pid
查看相應的exe文件:
file coreFile
gdb -c coreFile
readelf -h coreFile
利用core分析程序問題:
gdb -c coreFile exeFile
gdb exeFile coreFile
backtrace, bt 2(打印2層棧)
gdb的使用
開啓:gdb exeFile
給exe文件傳入參數:set args/run -t 5 -i data/rtp.data
查看代碼:set/show listsize, list +/-, list 151, list funcName, list 45, 49
(gdb) list wiucs::RecordConvert::convert
打斷點:break 151; b filename:151; b WebmMuxer::open;
break 199 if x == 2(x若是局部變量,則需要到此代碼處,再打斷點)
watch x > 2(x處理同上,x>2的值若有改變,則斷點產生)
斷點管理:delete 4(斷點號), disable/enable 4, clear 151(代碼行號), tbreak 151
查看變量:print varName; display/undisplay varName(遇斷點時,自動顯示);
whatis mediaHead(查看結構體);
set print pretty on
(gdb) p ntohs(seqnum)
控制流程:run, next, step(into func), finish(outof func), continue/until 159,
改流程:return 111, jump 159(直接跳到159行), signal 11(發段錯誤信息使程序停止執行)
設置值:set variable var_p = (char *)malloc(2) or print var_p = ...
線程:thread 3(切換到線程3);
break 88 thread 3 if x == y // 當線程3執行到88行並且變量x和y值相等時中斷
查看信息:where, frame 9(進入9號幀), up / down-silently(上下移動幀),
info locals/args/threads/frame/line(當前幀下的信息)
(gdb) info all-registers 寄存器中放置了程序運行時的數據,比如程序當前運行的指令地址(ip),程序的當前堆棧地址(sp)
(gdb) disassemble func // 打印出彙編代碼
gdb問題:
有斷點停不下來 // 實際停下來了,只是按continue時,沒有返回,又按了一次,導致C兩次,斷點打印在前面
gcc 尋找頭文件
1. 當前文件夾; 2. -I ; 3. /usr/include 4. gcc的環境變量C_INCLUDE_PATH...
#include <系統路徑> // 查找順序 3, 4, 1, 2
#include “對此C文件的路徑” // 查找順序 1,2,3,4
生成靜態庫
1. gcc -c a.c // 編譯成.o
// ar命令中不能加-lXXX, ar: two different operation options specified
2. ar -rcs libXXX.a obj1.o obj2.o (ar=archive, r=replace, c=create, s=)
生成動態庫
gcc -fPIC -shared -o libxxx.so a.c b.c
gcc -fPIC -o a.o -c a.c // gcc -c a.c
gcc -shared -o libxxx.so a.o // gcc -fPIC -shared -o libXXX.so a.o
查看庫中的內容
ar tv libXXX.a // 查看靜態庫含有的.o文件
nm -s libXXX.a // 查看靜態動態庫中的.o以及函數: U引用 T定義 W弱態
ldd libXXX.so // 查看so中的引用的so
庫的使用
1. -L; 2. LD_LIBRARY_PATH; 3. /etc/ld.so.conf ---> ldconfig ---> ld.so.cache; 4. /lib, /usr/lib
靜態庫:編譯時尋找的順序:1,2,3,4; 編譯完成後.a的代碼集成在exe中,執行時無需.a文件了。
動態庫:編譯時尋找的順序同上; 執行時仍然需要.so,其查找順序爲: -Wl,-rpath,/path1/:/path2(無空格,冒號),2,3,4
Q&A
0. LD_LIBRARY_PATH已經包含了動態庫所需要的路徑,但是程序還是找不到所需要的庫
場景1:LD_LIBRARY_PATH=...:A:...:B:...
A,B路徑都包含libjvm.so, libjava.so , 但是B=$JAVA_HOME/jre/lib/amd64/
結果:程序只在A中找所有需要的jre庫
Error occurred during initialization of VM
Unable to load native library: /opt/wiucs-cvt/libjava.so: cannot open shared object file:
No such file or director
解決方法: A,B位置互換; 或者刪除A中的.so
場景2:export LD_LIBRARY_PATH=/tmp;
當前shell調用 httpd, httpd 的子進程執行CGI程序,CGI程序需要新的SO
結果:儘管/tmp下有所需要的動態庫,但是CGI仍然引用不到
解決方法:export後僅當前shell(控制檯)及其子shell(httpd)可用,CGI是httpd的子進程所以引用不到;
指定執行動態庫時的搜索路徑:
mips2_fp_le-gcc -o getPageInfo -Wl,-rpath,/tmp $(OBJS) $(LIBS)
1. 多個-l的順序:根據依賴關係,反序排列!
g++ -o test IsacDecoder.cpp... -I... -L... -liSAC -lCNG -lsignal_processing -lpthread
2. 找不到庫中函數:nfs: server is working? // 動態庫在nfs server上
3. 程序既要和libhello進行靜態連接,又要和libbye進行動態連接,
其命令應爲: gcc testlib.o -o exefile -WI,-Bstatic -lhello -WI,-Bdynamic -lbye
-static -lXXX // 強制使用靜態庫(同時存在,默認動態庫優先)
4. 動態庫的應用:做插件 plugin // dlopen, dlsym
gcc 命令
gcc -o hello hello.c -save-temps(一步,保留中間文件)
預處理 gcc -o hello.i -E hello.c
編譯和彙編 gcc -o hello.o -c hello.i // ccl and as
鏈接 gcc -o hello hello.o // ld
生成依賴關係 gcc -MM a.c // a.o: a.c; -MMD: 生成.d .o
-Dmacro
相當於C語言中的#define macro
-Dmacro=defn
相當於C語言中的#define macro=defn
調試打印 #gcc -DDLD_DEBUG -O0 -g3 -Wall -c
#ifdef DLD_DEBUG
#define dbprintf(fmtstr, args...) \
{printf(fmtstr, ##args); printf("\n");}
#else
#define dbprintf(fmtstr, args...)
#endif
基本
0. 工具:Enterprise architecture
1. 可執行文件的執行時間 time ./test
2. 一般的系統都把內核源碼放在/usr/src下面
3. #include <math.h> -lm 一定要加上
4. could not read symbols: Malformed archive libCNG.a 移動位置後 失效 ?
5. case UE_KEY_SK01 ... UE_KEY_SK06: ??
6. static: C中表示本地文件,不能被異地引用 && 多次重入函數時引用上次保存的值
類中static 的數據,需要在外部進行初始化,因爲只能有一份。 singleObj* singleObj::_Obj = NULL;
7. yasm是彙編編譯器:爲了提高效率用到了彙編指令的程序需要yasm
8. 結構體中的指定初始化
struct {
char exten[AST_MAX_EXTENSION];
char context[AST_MAX_CONTEXT];
} pickup = {
.exten = "",
};
9. ptrdiff_t: 兩個指針相減的結果,long int, stddef.h(cstddef)
10. 把不同命令空間裏的類作爲友類:在各自類的頭文件中,對另一個類進行前向聲明。
不需要包含對方的頭文件(聲明瞭可編譯,鏈接時從動態庫以及頭文件中去找?)。
如:SessionRecord 的友類是 ConvertToWebm,這樣後者就可以訪問前者的私有成員。
SessionRecord.h: // the same with COnvertTowebm.h
namespace erizo{
class ConvertToWebm;
}
namespace wiucs{
friend class erizo::ConvertToWebm;
class SessionRecord{
}
}
11. list.assign(3, 7); // 3重複7次賦值
list.assign(listA.begin, listA.end) // 範圍賦值
12. 類之間的關係:
關聯association: A中有B的引用或變量,固定性
泛化generalization: 繼承
依賴dependency: 局部變量,方法參數,偶然臨時性
聚合agregation: 個體與羣體
組合composite: 部件與整體
13. 編譯64位: 不一定在64位機器上編譯; 編譯參數加上 -m64 ;
需要安裝完整版gcc, sudo apt-get install gcc-multilib
14. join() // 主線程等待分支線程結束: branch_thread_.join()
注意控制使得有循環的分支線程可以結束掉
常用函數以及處理
日誌:
c/C++: log4cxx,這個是Apache的開源,強烈建議C++用戶使用,跨平臺,支持多線程等優勢;
這個容易導致程序崩潰:log4Cplus
open VS fopen
open: 系統調用,返回文件描述符;設備文件只能用open
saveFd = open("/tmp/CLI_traceRoute.log", O_RDWR | O_CREAT | O_TRUNC, 0766);
write...
lseek(saveFd, 0, SEEK_SET);
ret = read(saveFd, buf, MAXBUF);
close(saveFd);
open/close, read/write, getc/putc, getchar/putchar 等。
fopen:標準庫函數(調用open),返回FILE指針;可移植;用緩存實現
FILE *fp = fopen("/proc/net/route", "r");
while (fgets(buf, sizeof(buf), fp))
fclose(fp);
fopen/fclose/freopen, fread/fwrite, fgetc/fputc, fgets/fputs, fseek/ftell/rewind等
寫文件後再用rewind()不起作用 // 關閉後,重新打開
比較:
輸出: fprintf (file或者描述符) vs sprintf(stringBuf),snprintf,vsnprintf(可變長的buf)
printf("ID:%x", this); // 打印對象; 後面加fflush(stdout);可提高打印效率
輸入: fscan (read from file)
網絡字節序轉換
uint16_t curSeq = ntohs(rh->seqnum);
uint32_t curTs = ntohl(rh->timestamp);
修改打印字符串的顏色
// "\033[0;34m" = blue "\033[0m" = none
snprintf(buf, size, "\033[0;34m[%d/%02d/%02d %02d:%02d:%02d] %s\033[0m",
1900+tm->tm_year, 1+tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, content);
opendir // 目錄下的目錄流
readdir // 目錄的特性
stat(fullName, &dstat)
S_ISDIR(dstat.st_mode)
closedir(dir);
if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) //#include <io h="">
chdir(url + 1) != 0 // change cur process work path //unistd.h
if(realpath(purl + 1, realpath_buff) != NULL) // 由相對路徑得到絕對路徑
包裹函數,安全的函數
snprintf(緩存地址,長度,格式,參數1...)
fgets(gets) strncpy(strcpy) strncat(strcat)
各種字串之間的轉換
其他類型(String, Qstring, Cstring)先轉換爲基本類型char*, 然後再轉換
string - char*
string str1(str2); // const char* str2 = "char";
char* str2 = const_cast<char>(str1.c_str());// string str1 ="string";
QString - char*
QString qstr(QString::fromLocal8Bit(str)); // const char* str = "string.";
const char* str2 = qstr.toLocal8Bit();
QString - string
QString s2q(const string &s)
{
return QString(QString::fromLocal8Bit(s.c_str()));
}
string q2s(const QString &s)
{
return string((const char *)s.toLocal8Bit());
}
CString - char*
char *ch = cstr.GetBuffer(cstr.GetLength() + 1); // CString cstr = "cstring.";
cstr.ReleaseBuffer();
系統執行
system(buf); // sprintf(buf,"/etc/network.rc LOAD&");
設置非阻塞
fcntl(sockfd ,F_SETFL, O_NONBLOCK);
信號以及鬧鈴
sigaction(SIGALRM, &sa, NULL); //他是POSIX的信號接口,而signal()是標準C的信號接口
alarm(TIMEOUT) >= 0 // 經過指定秒數後,給當前進程發送 SIGALRM 信號;後一個鬧鐘將會取消前一個,並從0開始計時,返回前個鬧鐘剩餘的秒數。
shutdown(a_c_w, SHUT_WR); //這樣關閉套接字更安全比其他方式
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
是作用於數據拷貝在兩個文件描述符之間的操作函數.這個拷貝操作是內核中操作的,所以稱爲"零拷貝".//#include <sys h="" sendfile="">
sendfile函數比起read和write函數高效得多,因爲read和write是要把數據拷貝到用戶應用層操作.
url = alloca(strlen(buf) + 12); // alloca 是在棧上分配空間的,儘量不要用。
strtok VS strtok_r
分別使用兩個 strtok ,會互相干擾(函數中的靜態指針,指向下個字串的)
pStr = strtok_r(buf, "\n", &outer_ptr);
sscanf會從buffer裏讀進數據,依照argument的設定將數據寫回。
sscanf與scanf類似,都是用於輸入的,只是後者以鍵盤(stdin)爲輸入源,前者以固定字符串爲輸入源。
count = sscanf(purl, " %[^ ] HTTP/%d.%*d", buf, &blank);
從輸入buf以及各式,生成所需字串 sscanf(data,"username=%[^&]&password=%[^&]",username,password);
#include <string.h>
char *strerror(int errnum);
int strerror_r(int errnum, char *buf, size_t n);
說明,對於函數strerror_r,第一個參數errnum是錯誤代碼,第二個參數buf是用戶提供的存儲錯誤描述的緩存,第三個參數n是緩存的大小。
數組
char array[10];
&array = array // 其值相等,不表示賦值
But, (&array + 1) != (array + 1)
// 數組名是數組第一個元素的地址,常量不可改變。所以
char * p = NULL; // &p爲指針變量存放的地址。&array 常量無需存放的地址,表示整個數組的地址
func(char ** p); // func(&array); 是錯誤的,其值等於array, 並沒有取得二級地址。
指針的指針:
指針的初始值爲NULL,把指針的地址記住,分配一段空間後,把分配的空間的地址通過剛纔的記住的指針的地址寫到指針的值中 指
針與引用的比較
int *p; VS int a; int &v = a; //引用必初始化
int *p = &a; VS 引用不能修改
函數返回char *
如果返回的是棧:野指針,因爲函數返回時棧被回收,亂指一氣
堆:誰釋放
全局:擴大作用域
在函數中定義靜態數組: static char value[64]; //如果不是多線程重入,static 也是不錯的選擇
網絡通信中的數據傳輸——————————採用外部表示法
網絡層中:數據以二進制表示
異構機: 指硬件不同,數據表示也不同
如
A:大端 32位 VS B:小端 16位 // 整數表示
C: ASCII VS B: unicode // 字符表示
外部表示法: SUN XDR ---> ASN.1 --> XML
高位低位的轉換寫法:
低位字 翻到高位字
低位字節翻到高位字節
比如1030 0f00 寫爲高位低位:
低位字 翻到高位字 -》0f00 1030,
然後低位字節翻到高位字節-》000f: 3010,完成。
然後寫成20位地址模式:高位字左移12位,得到 f000:3010
字串轉化爲長整形
char buffer[20]="10379cend$3";
char *stop;
printf("%d\n",strtol(buffer, &stop, 2)); //stop返回非法字符的首地址; 2爲轉換的2進制
printf("%s\n", stop);
輸出結果:2, 379cend$3
16進制的數字40轉換爲10進制串
char message[3];
sprintf(message, "%d", 40); //字串40
// 將字串40按照16進制來轉化,得到10進制數字
long int prelen = strtol(message, NULL, 16);
sprintf(message, "%ld", prelen); // print str "64"
字串轉double
strtod > Convert string to double
atoi > Convert string to int
atol > Convert string to long int
字串複製
t = strdup(s); // 函數內分配內存
free(t); // don't forget!
字串比較,忽略大小寫
strcasecmp
在源字串中查找目的字串中任一字符,並返回第一個找時的地址。
urlp = strpbrk(iobuf, " \t");
result = strpbrk( string, "0123456789" );//在string中找出最先出現0~9中某一個字符的位置
字串中查找字符
tptr = strchrnul(urlp, ' '); // 未找到,返回串尾
script = strchr(script + 1, '/') // 未找到,返回NULL
char * p = strrchr(buf, ' '); // 反向搜索字符
小寫字符變大寫
0100 0001 65 41 A
0110 0001 97 61 a
ch = (buf[0] & ~0x20); /* toupper if it's a letter */
C 正則表達式函數
#include <regex h="">
regcomp(結構體指針, 正則表達式,標誌);
regexec(編譯好的結構體, 待查找的字串,找到的個數,找到的結構體數組,標誌);
打印N個相同的字符,且字符數字爲變量
fprintf(stderr, "%*c ^\n", iLen, ' ');
</regex></sys></char></io>
C++文件包含C的函數
#ifdef __cplusplus
extern "C" {
#endif
...
...
...
#ifdef __cplusplus
}
#endif
C文件包含C++的函數
1. 將c文件需要的c++函數提取出來,放到另一個單獨的c++文件中,
2. 並在該文件及其頭文件都加extern "C"
3. 然後在c文件中include 其頭文件即可
頭文件
#ifndef __INCfooLibh
#define __INCfooLibh
#include
#define
const int // 常量定義塊
typedef struct //複合類型定義塊
void func(void); //函數原型說明塊
#endif /* __INCfooLibh */
數組內元素的個數
#define ARRAY_SIZE(x) ( (unsigned) ( sizeof(x) / sizeof((x)[0]) ) )
// x should be arrayName, not pointer to Array!!!!!!!!
int a = sizeof(p) ; // 指針的長度爲4
int b = sizeof((p)[0]); // 元素的長度可能爲8
所以 numofData = ARRAY_SIZE(p); //0.
定義數組個數
1、#define LISTEN_NUM 10
2、const int LISTEN_NUM = 10;
UserProfile users[LISTEN_NUM];
若用2的方式,運行時才確定,所以用gcc編譯會出現Error: variably modified 'users' at file scope
改成1的形式,則沒有報錯信息。編譯時確定。
連接符##和#轉字符串
// 因爲是C語言宏定義的,所以只在編譯時起作用,運行時不行
#define A(x) T_##x //字串連接: A(1)------〉T_1
#define B(x) #@x //加單引號: B(1)------〉'1'
#define C(x) #x //加雙引號: C(1)------〉"1"
例子1: #define paster(n) printf( "token" #n " = %d\n", token##n )
那麼paster(9)在編譯時,上面的這句話被擴展爲: printf( "token" "9" " = %d", token9 );
例子2: #define CLI_RINGTONE_LINE(i) <a>RINGTONE_LINE##i
</a> #define _GETSTR(test) #test
#define GETSTR(test) _GETSTR(test)
printf("%s", GETSTR(CLI_RINGTONE_LINE(2))); // 內外的宏都展開,則 output is “<a>RINGTONE_LINE2“
#define</a> GETSTR(test) #test // 如果沒有中間層的宏,則 output is ”CLI_RINGTONE_LINE(2)“
可變參數
// 用可變參數宏(variadic macros)傳遞可變參數表
#define dgbmsg(fmt,...) printf(fmt,__VA_ARGS__) // #define debug(...) printf(__VA_ARGS__)
// GCC 宏前面加上##的作用在於,當可變參數的個數爲0時,這裏的##起到把前面多餘的","去掉的作用,否則會編譯出錯
#define dbgprint(format,args...) fprintf(stderr, format, ##args)
1) __VA_ARGS__ 只有gcc支持,C++不支持。 // #include <stdarg h="">
2) __FILE__ 宏在預編譯時會替換成當前的源文件名
3) __LINE__ 宏在預編譯時會替換成當前的行號
4) __FUNCTION__ 宏在預編譯時會替換成當前的函數名稱
1. 變參的實現
#include <stdarg.h>
wiCallCtrlSyslog(const char *_format, ...)
{
va_list ap; // 分配存放變參的內存 char*
va_start(ap, _format); // 初始化,確定變參開始位置
rc = vsnprintf(fmt_buf, 255, _format, ap); // vsnprintf函數:格式化字符串複製
va_end(ap);
printf("[Call Ctrl] %s", fmt_buf);
}
2. 例子:
有時,我們想把調試信息輸出到屏幕上,而有時則又想把它輸出到一個文件中,可參考下面的例子:
//debug.c
#include <stdio h="">
#include <string h="">
//開啓下面的宏表示程序運行在調試版本, 否則爲發行版本, 這裏假設只有調試版本才輸出調試信息
#define _DEBUG
#ifdef _DEBUG
//開啓下面的宏就把調試信息輸出到文件,註釋即輸出到終端
#define DEBUG_TO_FILE
#ifdef DEBUG_TO_FILE
//調試信息輸出到以下文件
#define DEBUG_FILE "/tmp/debugmsg"
//調試信息的緩衝長度
#define DEBUG_BUFFER_MAX 4096
//將調試信息輸出到文件中
#define printDebugMsg(moduleName, format, ...) {\
char buffer[DEBUG_BUFFER_MAX+1]={0};\
snprintf( buffer, DEBUG_BUFFER_MAX \
, "[%s] "format" File:%s, Line:%d\n", moduleName, ##__VA_ARGS__, __FILE__, __LINE__ );\
FILE* fd = fopen(DEBUG_FILE, "a");\
if ( fd != NULL ) {\
fwrite( buffer, strlen(buffer), 1, fd );\
fflush( fd );\
fclose( fd );\
}\
}
#else
//將調試信息輸出到終端
#define printDebugMsg(moduleName, format, ...) \
printf( "[%s] "format" File:%s, Line:%d\n", moduleName, ##__VA_ARGS__, __FILE__, __LINE__ );
#endif //end for #ifdef DEBUG_TO_FILE
#else
//發行版本,什麼也不做
#define printDebugMsg(moduleName, format, ...)
#endif //end for #ifdef _DEBUG
int main(int argc, char** argv)
{
int data = 999;
printDebugMsg( "TestProgram", "data = %d", data );
return 0;
}
</string></stdio></stdarg>
守護進程
單獨的守護進程:httpd
/etc/init.d
超級守護進程:多了個一個管理員xinet,並且調用下面的進程時,分爲多線程,單線程形式
/etc/xinet.d
#include <unistd.h>
int daemon(int nochdir, int noclose); //成功返回0,失敗返回-1
daemon()函數,主要用於某些程序希望自己脫離終端的控制而運行於後臺的情況。
除非nochdir爲非零值,如果nochdir爲0,那麼daemon會從當前目錄,更改到根目錄(“/”)下運行。 // chdir
除非noclose爲非零值,如果noclose爲0,那麼daemon會將標準輸入,標準輸出,標準錯誤輸出重定向到/dev/null。 // dup2
父進程自殺,讓子進程成爲孤兒進程。
子進程創建新的會話,併成爲該會話的頭領進程 // setsid
開發問題
1. buf[10]設置過小,實際可能寫入了12個數據,從而導致程序掛掉(退出函數時纔出錯,可能退出時在回收資源時掛掉)
2. 初始化時,正確設置初始值;用完後及時清空問題,確保下次正確執行
3. 多線程對共享資源進行搶佔,加鎖確保共享資源不被破壞。一個線程寫,一個線程讀,也要加鎖;讀操作,其本質可能會對資源進行寫操作。
4. main() 放在namespace裏面,就報錯:無定義。
5. QT4安裝所需的庫
sudo apt-get install libx11-dev libfreetype6-dev libavahi-gobject-dev libSM-dev libXrender-dev libfontconfig-dev libXext-dev<p>
6. 安裝指定版本的glibc
./busybox: /lib/libc.so.6: version `GLIBC_2.7' not found (required by ./busybox)
檢查當前的版本: ll /lib/libc.so.6
下載: wget http://ftp.gnu.org/pub/gnu/glibc/glibc-2.12.1.tar.gz
配置 # ./glibc-2.12.1/configure --prefix=/usr/local/glibc2.12.1/ --with-headers=/usr/include
編譯 # cd glibc-2.7 ; make ; make install
7. 在ubuntu中LD_LIBRARY_PATH不起作用。據說因爲安全原因,Linux系統做了限制。
8. 注意不同命名空間中,攜帶空間的名字: erizo::ConvertToWebm 中 wiucs::SessionRecord,
9. 注意 #ifndef XXX_H_,有可能這裏的名字寫錯,造成寫了頭文件但沒有被引用到
10. ConvertToWebm c 要消費,SessionRecord s 中生產的 std::list<queue> audio_list_
錯誤:c. list = s.list // 僅僅是賦值操作,後續s.list中的變化,不能反映到c.list中
正確:c 中包含s指針,c實際處理的是s的數據: this->ps->list
</queue></p>
CLI
CLIisWorking
ps |grep debugsh |grep -v grep > /tmp/clips.txt
ignoreOutput
g_saveFd = dup(1);
g_newFd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0766);
dup2(g_newFd, 1)
password
getchar() and save in the passwd[]
termios.h tcgetattr() and err = tcsetattr(fd, TCSAFLUSH, &term); // del or add ECHOFLAGS
array
char tmpbuf[MAXPARAMS][MAXPARAMNAME] = { {0} };
strcpy(tmpbuf[argc], temp); // temp is string
command tree
typedef struct cmd{
char *name;/*命令名稱*/
STUHELP help;
struct cmd *subCmd;/*子命令集指針*/
funcHandleCmd handleCmd;/*命令執行函數*/
EnCmdMode Auth;
} CMD;
CMD rootCMD[] = {
{"aec",
{"Acoustic Echo Cancellation commands\n",
"channelid [dev deviceid] {enable | disable | status}"},
&nullCMD, Aec, all_mode
},
};
pSubCommand = lookforSubCmd(pCmdName, pNodeCMD, &retChkCmd); // 檢查命令
if (NULL == pSubCommand) // 沒有這個命令 或者 找到兩個
else if (&nullCMD == pSubCommand) // 找完了OK
else //繼續找下一級
retChkArg = checkCmdArg(syntaxStr, startIndex, endIndex, argv, &cmdParams); //檢查參數
retChkGrp = checkGroup(startGrp, &endGrp, &argType, tmpArgStr); //loop {} [] XX
retFill = fillBraketParam(tmpArgStr, ¶mNo, pParams, argc, &index, argv); // [{} XXX {} YYY]
or retFill = fillParam(¶mNo, pParams, argType, tmpArgStr, argc, &index, argv);
readline
initialize_readline ();
rl_bind_key('?', cmd_help);
s = rl_copy_text(0, rl_point); // hostname> show ? s = show 得到提示字串後的輸入
return main(); //Solution the problem that using the "?" and "Tab" can not bind the Enter key
rl_bind_key('\t',cmd_tab_completer);
s = rl_copy_text(0, rl_point); //get input
_rl_replace_text(line, len, rl_point);
rl_insert_text(" ");
// while(1)
line = readline(prompt);
add_history(str);
execCmd(str);
free(line);
recursive readdir
void getLsStr(char *path, char *lsStr) call itself when stat tells it's S_ISDIR // my first
something about CLI
getopt, readline, lex and yacc, flex and bison
線程鎖
一個讀寫鎖同時只能有一個寫者或多個讀者(與CPU數相關)
一次只能一個線程擁有互斥鎖,其他線程只有等待
LINUX多線程互斥量和讀寫鎖區別
boost庫中提供了mutex類與lock類,通過組合可以輕易的構建讀寫鎖與互斥鎖。
mutex類主要有兩種:
獨佔互斥類: boost::mutex, 有lock和unlock方法,
共享互斥類: boost::shared_mutex, lock/unlock,還有shared_lock/shared_unlock。
lock類
獨佔鎖(寫鎖): boost::unique_lock<t>, T爲任意mutex
共享鎖(讀鎖): boost::shared_lock<t>中的T只能是shared_mutex類
upgrade_lock,它的最大特點就是與shared_lcok不互斥,與別的upgrade_lock和unique_lock互斥。
upgrade_lock可以升級爲upgrade_to_unique_lock。據boost文檔說也可以downgrade成shared_lock
boost:mutex:soped_lock // 定義範圍內加鎖有效
注意:
鎖時ABC的連環扣,解鎖需要按照這個順序
對隊列等的讀操作,實際有寫得動作,比如修改下標,所以還是要用寫鎖
從共享的數據,以及參與的線程,來制定鎖的方案。
</t></t>
算法
排序算法
穩定性:數值相同的兩個數,經過排序後,他們之間的相對位置保持不變,稱爲穩定排序。
內/外排序:待排序的數字都在內存,爲內排序;如果部分在內存,排序後調整外存上的數據,爲外排序。
時間/空間複雜度:計算複雜程度,存儲空間
選擇排序:選擇最小的放在第一個,剩下的選擇最小放第二個位置...
堆排序:建立堆(二叉樹),堆頂爲最大元素;堆頂與最後一個元素交換,建立堆...
插入排序:一個一個插入到前面有序的數列中
希爾排序:按照增量劃分組,組內插入排序,直到增量爲1
冒泡排序:相鄰兩個數比較排序,每輪最大的數沉底
快速排序:一趟掃描,按照基準元素排序,左邊的數<基準<右邊...
算法
CASE軟件(Computer Aided Software Engineering)。 在需求分析階段,系統分析與設計階段,系統開發及部署等方面有着強大的支持 交互圖(interaction),協作圖(communication)和時序圖(Timing), 狀態圖(State),部署圖(Deployment),組件圖(component),活動圖(Activity),
boost
#include <boost hpp="" asio="">
boost::asio::io_service &_ioservice
boost::asio::ip::udp::socket* _socket
= new udp::socket(_ioservice, udp::endpoint(udp::v4(), port));
boost::asio::ip::udp::endpoint to_point(
boost::asio::ip::address::from_string(ip), port);
發送端:socket.send_to(發送到哪裏endpoint==ip,port)
//async_receive_from異步接收,不阻塞; receive_from沒有收到數據時,不能返回
接收端:_socket(用誰接收==port)->async_receive_from()
#include <boost hpp="" mutex="" thread="">
boost::mutex _socketMutex;
_socketMutex.lock();
_socketMutex.unlock();
#include <boost hpp="" array="">
boost::array<char buf_size=""> _recv_buf;
boost::asio::buffer(_recv_buf)
#include <boost hpp="" bind="">
boost::bind(&boost::asio::io_service::run, &_ioservice)
#include <boost hpp="" thread="">
boost::thread _thread;
_thread = boost::thread(&ForwardSender::send, this);
</boost></boost></char></boost></boost></boost>
<boost hpp="" asio=""><boost hpp="" mutex="" thread=""><boost hpp="" array=""><char buf_size=""><boost hpp="" bind=""><boost hpp="" thread="">
</boost></boost></char></boost></boost></boost>
<boost hpp="" asio=""><boost hpp="" mutex="" thread=""><boost hpp="" array=""><char buf_size=""><boost hpp="" bind=""><boost hpp="" thread="">