C言語プログラミング


C言語プログラミング
1.sscanf()
sscanf()はscanf()と同様に入力に用いられるが,後者はキーボード(stdin)を入力源とし,前者は固定文字列を入力源とする.
ヘッダファイル:#include
フォーマット:int sscanf(const char*buffer,const char*format,[argument]...);
例:
char *p = "123";
int val = 0;
sscanf(p,"%d",&val);
則val==123.
2.ゼロ長配列
組み込み開発、特にlinux kernelではゼロ長配列によく使用され、ゼロ長配列メンバーを可変長配列のプレースホルダとして使用できます.次のように定義します.
typedef struct my_data
{
	int val;
	int len;
	char var[0];//       
}data_t;

メンバーvar[0]はゼロ長配列であり、その長さがゼロである、すなわち記憶領域を占めないため、以上の構造体が占有する空間sizeof(struct my_data)==sizeof(val+len)である.では、var[0]メンバーはどんな用途がありますか?その機能は、可変長の配列を定義し、var[i]を介して構造体のメンバーlenの後のi番目のデータにアクセスすることである.
次のようになります.
#define LEN		10
data_t *test = malloc(sizeof(data_t)+LEN);
test->var[8] = 5;//    LEN    

3.extern修飾関数ヘッダファイルで関数を宣言する場合、またはCファイルで関数を定義する場合、externを追加するかどうかは同じです.この2つの場合、関数のデフォルトはexternです.
4.配列名が関数ポインタに等しくない
たとえば、配列の長さをsizeof()で計算できます.
char  p[100];
sizeof(p) = 100;
char *p;
sizeof(p)=4;
したがって、配列名と関数ポインタの違いに注意します.
5.構造体の要素のオフセットを計算する構造体を定義する
struct OffsetTest
{
	char a;	//offset->0
	char b;	//offset->1
	char c;	//offset->2
	char d;	//offset->3
	int e;	//offset->4
	int f;	//offset->8
};
は、構造体の任意の要素の相対的なオフセットを、以下のように定義されたマクロによって計算することができる.
#define OFFSET_OF(struct_name, field)   					((int)&((struct_name *)0)->field)
であり、計算構造体のサイズはsizeof()演算子で直接計算することができる.
6.itoa()とatoi()関数
itoa():整数値を文字列に変換し、atoi()は逆の操作を実現します.
この2つのライブラリ関数をサポートしないシステムでは、類似の機能の関数を自分で作成できます.次のようになります.
int my_atoi(char *str)
{
	int i = 0,ret = 0;	
	ret = (*str++ - '0');
	while(*str)
	{
		ret = ret*10 + (*str - '0');
		str++;
	}
	return ret;
}

7.循環シフト動作
#define ROTATE_LEFT(x,n) ((x) << (n)) | ((x) >> (sizeof(x)*8 - (n)))
#define ROTATE_RIGHT(x,n) ((x) >> (n)) | ((x) << (sizeof(x)*8 - (n)))

8.strcpy()、strncpy()とstrlcpy()
A.strcpy()
strcpy()は文字列をコピーするときに「0」を終了フラグとし、ソース文字列が「0」で終わらないとプログラムがデッドループに陥る.宛先アドレスの記憶領域がソース文字列の長さよりも小さい場合、メモリオーバーフローも発生します.したがってstrcpy()の使用には一定の安全問題があり、使用時には慎重にしなければならない.
B.strncpy()
strncpy()はstrcpy()に対して比較的安全であるが、ソース文字列の文字数(末尾を含まない0)が宛先空間の大きさに等しい場合、宛先アドレスの後に0を補うことは保証されないため、strncpy()を使用する場合、コピーが完了した後、宛先文字列の末尾に0を埋めるのが標準的である.
C.strlcpy()
strlcpy()はANSI Cの標準コンテンツではありませんが、linuxではよく使われています.この関数は、最大コピー先の空間サイズから1文字を減算し、末尾で自動的に0を補うことを保証するので、より安全です.
9.整数Nの階乗を求める(n!)
unsigned int factorial(unsigned int n)
{
	unsigned int result = 0;
	if(n >= 2)
	{
		return n*factorial(n-1);
	}
	return 1;	
}

10.カンマの使い方
A.カンマはカンマ演算子としてカンマ式を構成し、順序評価演算子とも呼ばれる
この場合、各式の値を左から右に順に求めます.カンマ式全体の値は、次のように右端の式の値に等しくなります.
	int a = 1,b = 2;
	printf("Result = %d!
",(a = b+a,a));
は、上述したコード実行の結果が3である.
B.カンマを区切り文字とする
printf関数では、パラメータの計算順序は右から左になります.
次のようになります.
	int a = 1,b = 2;
	printf("Result = %d,%d,%d,%d!
",a,b,a += b,b += a);
上記コードの実行結果は、3,4,3,4,4である.
11.マクロにおけるローカル変数の定義およびマクロ関数による戻り値の取得
#define get_val(n)			\
({					\
	unsigned int v;			\
	if (n > 100)			\
		v = 1;			\
	else				\
		v = 0;			\
	v;				\
})

12.変数パラメータのマクロ関数
#define LOG(fmt,arg...)				printf(fmt,##arg)

13.fflush()とfsync()
int fflush(FILE*stream):ファイルシステムのキャッシュにデータをブラシするしかなく、本当にストレージメディアに書かれていません.
 int fsync(int fd):データを記憶媒体にリフレッシュします.
しかし、fsync()のパラメータはファイル記述子であるため、fopen()でファイルを開く場合、ファイルフローポインタをファイル記述子に変換する必要があり、fileno()関数で変換することができる.
14.メモリアドレスの位置合わせ
プログラミング中、あるいはプログラムを最適化する必要がある場合、次の文のキーワード__のように、アドレスを文字で揃えなければならない変数や配列など、よく使われる.align(4)は、定義された配列のヘッダアドレスを4バイトで整列させるために使用される.
__align(4) uint8_t DataBuf[2048];

15.ヘッダファイルの適用
static CommandInfo commands[] = {
#include "my_commands.h"
};