2012年2月1日 星期三

位元處理函式

/******************************************************
function name :bitclr
description :清除指定位元(0)
Ex: bitclr(0xff,3)
11111111 -> 11110111
bitaddr :0~31
******************************************************/
unsigned int bitclr(unsigned int srcvalue,unsigned char bitaddr)
{
unsigned int mask=1;
return srcvalue&(~(mask< 01011101
bitaddr :0~31
******************************************************/
unsigned int bitset(unsigned int srcvalue,unsigned char bitaddr)
{
unsigned int mask=1;
return srcvalue|(mask< 10001001
bitaddr :0~31
******************************************************/
unsigned int bitinv(unsigned int srcvalue,unsigned char bitaddr)
{
unsigned int mask=1;

if((srcvalue>>bitaddr)&0x00000001==1)
return srcvalue&(~(mask< false
bitaddr :0~31
return : 1:true , 0:false
******************************************************/
unsigned char bitcmp(unsigned int srcvalue,unsigned char bitaddr)
{

if((srcvalue>>bitaddr)&0x00000001==1)
return 1;
else
return 0;
}

/******************************************************
function name :bitget
description :回指定bit 為 0 或 1
Ex: bitget(0x55,3)
01010101 -> 0
bitaddr :0~31
return : get bit value
******************************************************/
unsigned char bitget(unsigned int srcvalue,unsigned char bitaddr)
{
return (srcvalue>>bitaddr)&0x00000001;
}

/******************************************************
function name :bitput
description :設定指定bit 為 0 或 1
Ex: bitget(0x55,3,1)
01010101 -> 01011101
bitaddr :0~31
return : put bit value
******************************************************/
unsigned int bitput(unsigned int srcvalue,unsigned char bitaddr,unsigned char value)
{
if (value==1)
return bitset(srcvalue,bitaddr);
else
return bitclr(srcvalue,bitaddr);

}

/******************************************************
function name :bitSwap
description :將傳入數值low 與 high 位元完全互換
Ex: bitSwap(0x55)
01010101 -> 10101010
return : swap bit value
******************************************************/
unsigned int bitSwap(unsigned int value)
{
unsigned int tmpbit;
unsigned char i;

tmpbit=value;
for (i=0;i<32;i++) { tmpbit=bitput(tmpbit,31-i,bitget(value,i)); } return tmpbit; } 





C語言不定參數

在C 語言我們常常見到不定參數的使用,像是 prinft() 與 scanf() 
這些函數的定義使用符號 ... 來表示不定參數,如int printf( const char* format, ...);
在內部則是使用 va 系列巨集來實現的
   va_list                                          //不定長度型態

   void va_start( va_list arg_ptr, prev_param );    //啟始不定長度引數的巨集
   type va_arg( va_list arg_ptr, type );            //讀取不定長度引數的巨集
   void va_end( va_list arg_ptr );                  //結束不定長度引數的巨集 


va 系列的巨集定義如下:
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int)-1)) 

#define va_start(ap,v) ( ap=(va_list)&v + _INTSIZEOF(v)) 
#define va_arg(ap,t) (*(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))) 
#define va_end(ap) (ap = (va_list)0 )

簡單的範例:

#include 
#include 
#include 
void CLI_TMP(unsigned int type,...);

int main(int argc, char *argv[])
{
    char d[10]="ABC";
    
    CLI_TMP(0,10,20,30,d,"ddsfssf",'c');


    system("PAUSE");
    return 0;
}

void CLI_TMP(unsigned int type,...)
{
    va_list argptr;
    char temp_buf[256];
    int a,b,c;
    char *d,*e;
    char f;
    
    va_start(argptr, type);

    a = va_arg (argptr,int);
    b = va_arg (argptr,int);
    c = va_arg (argptr,int);
    d = va_arg (argptr,char*);
    e = va_arg (argptr,char*);
    f = va_arg (argptr,int);
    
    strcat(d,"aaa");
    va_end(argptr);
    
    printf("%d,%d,%d,%s,%s,%c\n",a,b,c,d,e,f);
} 

link from:http://blog.yam.com/ddy1280/article/2095414

使用awk 解析資料

使用 Linux 愈久,愈深深的被 Linux 的系統架構與極具彈性的 script 與工具吸引
原來,解決問題只要短短的一行指令,相信這是許多程式設計人員嚮往的事

最近工作上需要從dhcpcd 取得一些額外的資訊,所以在system call 所沒有有提供的部份,就要從記錄檔裡分析
通常,我們在 linux 下常見的文字檔是DSV 格式(Delimiter-Separated Values)像是/etc/passwd 或是以Space 分隔
在Windows 則常見 INI 格式

以往要取得這類文件的某行或某列的特定資料,通常會寫個程式,然後開檔,一行一行讀取,讀到某行,再進行分析,這樣的做法真的很累,以前我就是這樣做的
而現在,grep 與 sed ,或是 awk 幫我完成大部份工作
例1: 
資料檔 aa.txt
Destination    Gateway       Genmask         Flags Metric Ref

192.168.100.0  *             255.255.255.0   U     3      1  
172.16.100.0   *             255.255.255.0   U     5      0  
172.16.200.0   *             255.255.255.0   U     3      0  
default        172.16.100.73 255.255.255.0   U     3      0  


        FILE *fp;

    fp = popen("cat aa.txt | grep default |awk '{print $2}'","r");
    if (fp !=NULL)
    {
        fgets(buf,16,fp);
        pclose(fp);
    }
使用grep 與 awk 分析資料再使用popen()開啟管線,取回的buf,就是172.16.100.73


例2:
資料檔  dhcpcd.info
[dhcpcd]
IPADDR=172.16.100.239
NETMASK=255.255.255.0
NETWORK=172.16.100.0
BROADCAST=172.16.100.255
GATEWAY=172.16.100.73
DNS=192.168.1.254
DHCPSIADDR=172.16.100.73
DHCPCHADDR=00:05:65:71:1F:EA
DHCPSHADDR=00:90:CC:40:25:F9

    FILE *fp;

    fp = popen("cat dhcpcd.info |awk -F = '/GATEWAY/{print $2}'","r");
    if (fp !=NULL)
    {
        fgets(buf,16,fp);
        pclose(fp);
    }
使用awk 取得 Name=Value 格式的資料,這種格式常見於 windows INI 
最後的結果buf 就是我們要的 172.16.100.73  (Gateway Address)

解說: awk -F fs   意指,設定分隔的字串,在這個例子裡,資料是以 = 符號區分欄位的
所以 fs 要設為 = 符號,/GATEWAY 意指,搜尋GATEWAY 的那一行,
/{print $2}  意指,列印出第二欄的資料



awk 真的是很值得學習的script ,不只在 linux 才有,windows 平台也有喔(按此下載)

參考資料:
Scripts 大集合
AWK Tutorial Guide


使用C 取得外部shell script回傳值(linux)

有時候我們為了提高程式的彈性,會使用shell script 來做部份的工作
再取得回傳值來判定正常或是異常
以下面的例子…使用script 判斷目錄是否存在~

#!/bin/sh
#check directory

if [ -d $1 ];then
   #do something...
   ls $1
   exit 0
else
   exit 2
fi

可直接在shell 下觀察回傳

echo $?

而在C 語言程式裡…若要取得執行外部shell script 的回傳值的話,如下所示 

#include

int main (int argc,char **argv)
{
    int ret=0;
    ret=system("./checkdir dir1");
    ret >>= 8;
    if (ret==2)
        printf("dir1 does not exist\n");
}

說明:
1.在shell script 裡是透過exit 返回時帶回傳值, 在C 與 shell 裡的慣例 0 為正常結束,非0 則為異常
2.在C 程式裡其中 ret 值要除以256才會得到與shell 傳回相符的值




【C語言】一堆子轉換函式

許多初學者而言,資料的轉換仍然是一個問題,在此整理一些函式說明如下:

大概分為三類
  1. 字串與數值轉換
  2. 位元順序轉換
  3. 網路位址轉換

字串與數值轉換
    常見的就是atoi(),atol(),atof(),itoa() ... 之類的,其中itoa() 不被gcc所支援,可透過sprintf()來實現轉換,並僅以atoi()與sprintf()為例
  
原型宣告使用方法使用時機
#include 
int atoi (const char *str);
int a;
a=atoi("100");
將數值字串轉換成整數
#include 
int sprintf (char *str,const char *format,...);
char s[10];
sprintf(s,"%s",100);
將數值轉換為字串


位元順序轉換
    位元序序轉換是因為x86 cpu讀取記憶體的順序與磁碟上存放的順序不同而造成的,x86架構是所謂的Little-Endian,在磁碟上儲存的位元組是照順序的,然而以32位元記憶體存取而言,會先從低位元開始讀取,例如…在磁碟上存放的資料是0x12345678,那麼讀進記憶體之後,就會是0x78 0x56 0x34 0x12
所以,從在儲存媒體與記憶體之間的資料需要轉換。另外就是用於Host Byte Order 與 Network Byte Order 互換,因為網路跨平台的特性,無論主機端是Big-Endian 或是Little-Endian 都要能正確地透過網路交換資料,所以在Socket定義上,Network Byte Order 採用 Big-Endian 。以下函式可達成轉換:
#include 

uint32_t htonl(uint32_t hostlong);//32位元資料轉換
uint16_t htons(uint16_t hostshort);//16位元資料轉換
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

僅以host 中32位元記憶體中資料 0x78563412 為例:
原型宣告使用方法使用時機
#include 
uint32_t htonl(uint32_t hostlong);
unsigned int a,b;
a=0x78563412;
b=htonl(a);
1.host轉換成network 順序
2.memory 資料寫入磁碟的轉換
(0x78563412-->0x12345678)
#include 
uint32_t ntohl(uint32_t netlong);
unsigned int a,b;
b=0x12345678;
a=ntohl(b);
1.network 轉換成host順序(0x12345678-->0x12345678)

網路位址轉換 
    網路位址轉換是32位元IP值與IP字串的轉換,例如我們所輸入的IP 192.168.100.111 是一組字串,但是socket api 接受的是32位元IP值,所以需要轉換,或是從socket api 取得的32位元IP值,要轉換成可顯示的字串格式,可例用下列函式:
#include 
#include 
#include 

char *inet_ntoa(struct in_addr in);
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);

原型宣告使用方法使用時機
#include 
#include 
#include  
char *inet_ntoa(struct in_addr in); 
char ipbuf[16];
struct in_addr addr;
addr.s_addr =0xC0A86401;
sprintf(ipbuf,"%s",inet_ntoa(addr));
32位元IP Address 轉換為IP字串

            
#include 
#include 
#include 
int inet_aton(const char *cp, \ struct in_addr *inp);
struct in_addr addr;
unsigned int ip;
ip=inet_aton("192.168.100,1",&addr);
IP字串轉換為32位元IP Address

How to use simple speedtest in RaspberryPi CLI

  pi@ChunchaiRPI2:/tmp $  wget -O speedtest-cli https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py --2023-06-26 10:4...