関連記事
GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ · GitHub
概要
以下、自分用のメモです。よく忘れるのでここにメモメモ。。。。
C言語でコンパイラに gcc とか clang 使っている場合、GCC拡張が使えます。
拡張って名前が付いているので、純粋なC規格には含まれていないものですが、知ってると便利なものが沢山あります。
実務で実装する場合は、MISRA準拠とかが結構多いので、そういうところでは使えないです。なので、あまり知られていないのかもしれませんね。
個人的に cleanup は、Goのdeferに近い動きになるので、めっちゃ便利です。ツールをC言語とかで作る場合はよく利用しています。
こんな感じ。
#include <stdio.h> #include <stdlib.h> static void fclosep(FILE **pf) { printf("CALL fclosep\n"); if (pf && *pf) { fclose(*pf); *pf = NULL; } } static void freep(void *p) { printf("CALL freep\n"); void **pp = p; free(*pp); *pp = NULL; } int process_file(const char *path) { FILE *fp __attribute__((cleanup(fclosep))) = fopen(path, "r"); char *buf __attribute__((cleanup(freep))) = malloc(4096); if (!fp || !buf) { return -1; // ここで return しても自動で fclose/free } fgets(buf, 4096, fp); printf("%s\n", buf); return 0; // ここでも同様に自動解放 } int main(void) { process_file("main.c"); }
$ gcc -o app main.c $ ./app #include <stdio.h> CALL freep CALL fclosep
よく利用されるもの
数が多いので、Claudeさんに手伝ってもらいました。
関数につけるもの
// 戻り値を無視した場合にコンパイラ警告を出す __attribute__((warn_unused_result)) int read_data(void *buf, size_t len); // 引数が NULL であれば未定義動作と明示(最適化ヒント) __attribute__((nonnull(1, 2))) int process(const char *path, void *buf); // 関数が戻らないことを明示(exit, abort 等) __attribute__((noreturn)) void fatal(const char *msg); // printf 系のフォーマット文字列チェックを有効化 // 第1引数: フォーマット文字列の位置, 第2引数: 可変引数の開始位置 __attribute__((format(printf, 1, 2))) void my_log(const char *fmt, ...); // インライン展開を強制 __attribute__((always_inline)) static inline int clamp(int v, int lo, int hi); // インライン展開を禁止 __attribute__((noinline)) void debug_dump(void); // 使用されていても「未使用」警告を抑制 __attribute__((unused)) static void legacy_func(void); // 非推奨マーク(呼び出し側に警告) __attribute__((deprecated("use new_func instead"))) void old_func(void); // 関数がグローバル状態を参照・変更しない純粋関数 __attribute__((pure)) // グローバル読み取りはOK __attribute__((const)) // グローバルアクセス完全禁止(より強い) int square(int x);
変数とか型につけるもの
// パディングを除去してメモリを詰める struct __attribute__((packed)) packet_header { uint8_t type; uint16_t length; uint32_t seq; }; // アライメントを指定 __attribute__((aligned(64))) static uint8_t dma_buffer[4096]; // キャッシュライン境界合わせ // 変数が使われなくても警告を抑制 __attribute__((unused)) static int debug_flag = 0; // 変数をBSSではなく特定セクションに配置 __attribute__((section(".flash_data"))) const uint8_t firmware_version[] = {1, 0, 0};
共有ライブラリで使う
// シンボルをエクスポート(デフォルト可視) __attribute__((visibility("default"))) int public_api(void); // シンボルを非公開(.so内部専用) __attribute__((visibility("hidden"))) static int internal_helper(void);
その他
// main() より前に実行される __attribute__((constructor)) static void lib_init(void) { // ライブラリの初期化処理 } // main() 終了後に実行される __attribute__((destructor)) static void lib_fini(void) { // ライブラリの後処理 } // 優先度指定(101〜65535、小さいほど先に実行) __attribute__((constructor(200))) static void init_phase2(void) { ... }
参考情報
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。