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ではゼロ長配列によく使用され、ゼロ長配列メンバーを可変長配列のプレースホルダとして使用できます.次のように定義します.
メンバーvar[0]はゼロ長配列であり、その長さがゼロである、すなわち記憶領域を占めないため、以上の構造体が占有する空間sizeof(struct my_data)==sizeof(val+len)である.では、var[0]メンバーはどんな用途がありますか?その機能は、可変長の配列を定義し、var[i]を介して構造体のメンバーlenの後のi番目のデータにアクセスすることである.
次のようになります.
3.extern修飾関数ヘッダファイルで関数を宣言する場合、またはCファイルで関数を定義する場合、externを追加するかどうかは同じです.この2つの場合、関数のデフォルトはexternです.
4.配列名が関数ポインタに等しくない
たとえば、配列の長さをsizeof()で計算できます.
char p[100];
sizeof(p) = 100;
char *p;
sizeof(p)=4;
したがって、配列名と関数ポインタの違いに注意します.
5.構造体の要素のオフセットを計算する構造体を定義する
6.itoa()とatoi()関数
itoa():整数値を文字列に変換し、atoi()は逆の操作を実現します.
この2つのライブラリ関数をサポートしないシステムでは、類似の機能の関数を自分で作成できます.次のようになります.
7.循環シフト動作
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!)
10.カンマの使い方
A.カンマはカンマ演算子としてカンマ式を構成し、順序評価演算子とも呼ばれる
この場合、各式の値を左から右に順に求めます.カンマ式全体の値は、次のように右端の式の値に等しくなります.
B.カンマを区切り文字とする
printf関数では、パラメータの計算順序は右から左になります.
次のようになります.
11.マクロにおけるローカル変数の定義およびマクロ関数による戻り値の取得
12.変数パラメータのマクロ関数
13.fflush()とfsync()
int fflush(FILE*stream):ファイルシステムのキャッシュにデータをブラシするしかなく、本当にストレージメディアに書かれていません.
int fsync(int fd):データを記憶媒体にリフレッシュします.
しかし、fsync()のパラメータはファイル記述子であるため、fopen()でファイルを開く場合、ファイルフローポインタをファイル記述子に変換する必要があり、fileno()関数で変換することができる.
14.メモリアドレスの位置合わせ
プログラミング中、あるいはプログラムを最適化する必要がある場合、次の文のキーワード__のように、アドレスを文字で揃えなければならない変数や配列など、よく使われる.align(4)は、定義された配列のヘッダアドレスを4バイトで整列させるために使用される.
15.ヘッダファイルの適用
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"
};