C プログラミング言語の拡張機能として作成された高レベルの汎用プログラミング言語。低レベルのメモリ操作機能に加えて、オブジェクト指向、汎用、関数型の機能を備えています。
C2059は、Visual Studioを使っているのであれば「メニュー->表示->エラー一覧」で表示されるエラーウィンドウで、そのエラーをダブルクリックするとエラーの場所に飛べるので、括弧の組み合わせが一致しているかを確認してください。
#defineで定義されているマクロがあると、マクロに括弧やカンマなどの区切りがあってわかりにくなる場合があります。
その場合には#includeや#defineのない新しい.cファイルを作ってコピーして確認すると、そのコード部分で組み合わせがおかしいのか、マクロでおかしいくなっているのかが調べられるかもしれません。
このエラーは自分で間違った箇所を探すしかありません。
構造体の宣言と同時に初期化するには、初期化子リストという方法があります。
libpngのコードがマクロ展開をたくさん使っているのでわかりにくいですが、以下のように順番に解釈していけばわかります。
/// pngpriv.h
#define PNG_KNOWN_CHUNKS\
PNG_CHUNK(IHDR, 0)\
PNG_CHUNK(PLTE, 1)\
PNG_CHUNK(IDAT, 2)\
PNG_CHUNK(IEND, 3)\
PNG_CHUNK(acTL, 4)\
PNG_CHUNK(bKGD, 5)\
PNG_CHUNK(cHRM, 6)\
PNG_CHUNK(cICP, 7)\
PNG_CHUNK(cLLI, 8)\
PNG_CHUNK(eXIf, 9)\
PNG_CHUNK(fcTL, 10)\
PNG_CHUNK(fdAT, 11)\
PNG_CHUNK(gAMA, 12)\
PNG_CHUNK(hIST, 13)\
PNG_CHUNK(iCCP, 14)\
PNG_CHUNK(iTXt, 15)\
PNG_CHUNK(mDCV, 16)\
PNG_CHUNK(oFFs, 17)\
PNG_CHUNK(pCAL, 18)\
PNG_CHUNK(pHYs, 19)\
PNG_CHUNK(sBIT, 20)\
PNG_CHUNK(sCAL, 21)\
PNG_CHUNK(sPLT, 22)\
PNG_CHUNK(sRGB, 23)\
PNG_CHUNK(tEXt, 24)\
PNG_CHUNK(tIME, 25)\
PNG_CHUNK(tRNS, 26)\
PNG_CHUNK(zTXt, 27)
/// pngstruct.h
#define PNG_CHUNK(cHNK, i) PNG_INDEX_ ## cHNK = (i), //これはPNG_KNOWN_CHUNKSの各行をenumの列挙子にするマクロ
typedef enum
{
PNG_KNOWN_CHUNKS // ここではPNG_KNOWN_CHUNKSをenumの項目に展開している
PNG_INDEX_unknown // この値は PNG_KNOWN_CHUNKSの最後の値+1。 PNG_KNOWN_CHUNKSの最後に27が定義されているので、その次の28。
} png_index;
/*
まずPNG_KNOWN_CHUNKSが展開され
typedef enum
{
PNG_CHUNK(IHDR, 0),
PNG_CHUNK(PLTE, 1)\
省略
PNG_CHUNK(zTXt, 27),
PNG_INDEX_unknown
} png_index;
のようになる。
さらに、展開されたPNG_CHUNKに上のマクロが適用されて
typedef enum
{
PNG_INDEX_IHDR = (0),
省略
NG_INDEX_zTXt = (27),
PNG_INDEX_unknown
} png_index;
という列挙型になります
*/
#ifndef PNG_RESTRICT
#define PNG_RESTRICT
#endif
typedef enum
{
handled_error = 0,
handled_discarded,
handled_saved,
handled_ok
} png_handle_result_code;
//---------------------------
typedef unsigned int png_uint_32;
typedef struct png_struct_def png_struct;
typedef png_struct* PNG_RESTRICT png_structrp;
typedef const png_struct* PNG_RESTRICT png_const_structrp;
typedef struct png_info_def png_info;
typedef png_info* PNG_RESTRICT png_inforp;
typedef const png_info* PNG_RESTRICT png_const_inforp;
#define PNG_HAVE_IHDR 0x01
#define PNG_HAVE_PLTE 0x02
#define PNG_AFTER_IDAT 0x08
#define PNG_HAVE_IDAT 0x04U
#define LZ77Min (2U+5U+4U)
//テストコンパイル用偽関数定義生成
#define PNG_CHUNK(cHNK, i) png_handle_result_code png_handle_ ## cHNK (png_structrp a, png_inforp b, png_uint_32 length) {return handled_ok;}
PNG_KNOWN_CHUNKS
//---------------------------
static const struct
{
png_handle_result_code(*handler)(png_structrp, png_inforp, png_uint_32 length);
png_uint_32 max_length : 12;
png_uint_32 min_length : 8;
png_uint_32 pos_before : 4;
png_uint_32 pos_after : 4;
png_uint_32 multiple : 1;
}
//これは直前の構造体の型の配列
read_chunks[PNG_INDEX_unknown] =
{
//この下の#defineはPNG_KNOWN_CHUNKの項目のマクロ展開で使うパラメーター
#define NoCheck 0x801U
#define Limit 0x802U
#define LKMin 3U+LZ77Min
#define hIHDR PNG_HAVE_IHDR
#define hPLTE PNG_HAVE_PLTE
#define hIDAT PNG_HAVE_IDAT
#define hCOL (PNG_HAVE_PLTE|PNG_HAVE_IDAT)
#define aIDAT PNG_AFTER_IDAT
#define CDIHDR 13U, 13U, hIHDR, 0, 0
#define CDPLTE NoCheck, 0U, 0, hIHDR, 1
#define CDIDAT NoCheck, 0U, aIDAT, hIHDR, 1
#define CDIEND NoCheck, 0U, 0, aIDAT, 0
#define CDtRNS 256U, 0U, hIDAT, hIHDR, 0
#define CDcHRM 32U, 32U, hCOL, hIHDR, 0
#define CDgAMA 4U, 4U, hCOL, hIHDR, 0
#define CDiCCP NoCheck, LKMin, hCOL, hIHDR, 0
#define CDsBIT 4U, 1U, hCOL, hIHDR, 0
#define CDsRGB 1U, 1U, hCOL, hIHDR, 0
#define CDcICP 4U, 4U, hCOL, hIHDR, 0
#define CDmDCV 24U, 24U, hCOL, hIHDR, 0
#define CDeXIf Limit, 4U, 0, hIHDR, 0
#define CDcLLI 8U, 8U, hCOL, hIHDR, 0
#define CDtEXt NoCheck, 2U, 0, hIHDR, 1
#define CDzTXt Limit, LKMin, 0, hIHDR, 1
#define CDiTXt NoCheck, 6U, 0, hIHDR, 1
#define CDbKGD 6U, 1U, hIDAT, hIHDR, 0
#define CDhIST 1024U, 0U, hPLTE, hIHDR, 0
#define CDpHYs 9U, 9U, hIDAT, hIHDR, 0
#define CDsPLT NoCheck, 3U, hIDAT, hIHDR, 1
#define CDtIME 7U, 7U, 0, hIHDR, 0
#define CDacTL 8U, 8U, hIDAT, hIHDR, 0
#define CDfcTL 25U, 26U, 0, hIHDR, 1
#define CDfdAT Limit, 4U, hIDAT, hIHDR, 1
#define CDoFFs 9U, 9U, hIDAT, hIHDR, 0
#define CDpCAL NoCheck, 14U, hIDAT, hIHDR, 0
#define CDsCAL Limit, 4U, hIDAT, hIHDR, 0
#define PNG_CHUNK(cHNK, index) { png_handle_ ## cHNK, CD ## cHNK }, //これは PNG_KNOWN_CHUNK を構造体の初期化子に展開するマクロ
//#define PNG_CHUNK(cHNK, index) { png_handle, CD ## cHNK }, //これは PNG_KNOWN_CHUNK を構造体の初期化子に展開するマクロ
PNG_KNOWN_CHUNKS //ここではPNG_KNOWN_CHUNKの各項目が、この上のPNG_CHUNKマクロによって、それぞれ構造体に展開される
#undef PNG_CHUNK
};
/*
つまり
PNG_CHUNK(IHDR, 0)\
PNG_CHUNK(PLTE, 1)\
のような項目が
{ png_handle_IHDR, CDIHDR} ,
{ png_handle_PLTE, CDPLTE} ,
と展開されて、さらに二つ目のCD*の部分もマクロ展開されることで
{ png_handle_IHDR, 13U, 13U, hIHDR, 0, 0} , //6個のフィールドがある構造体の初期化子
{ png_handle_PLTE, NoCheck, 0U, 0, hIHDR, 1} ,
のように構造体の初期化子になります。
よって、最終的には
static const struct
{
png_handle_result_code(*handler)(png_structrp, png_inforp, png_uint_32 length);
png_uint_32 max_length : 12;
png_uint_32 min_length : 8;
png_uint_32 pos_before : 4;
png_uint_32 pos_after : 4;
png_uint_32 multiple : 1;
}
read_chunks[28] = {
{ png_handle_IHDR, 13U, 13U, hIHDR, 0, 0} ,
{ png_handle_PLTE, NoCheck, 0U, 0, hIHDR, 1} ,
省略
{ png_handle_zTXt, Limit, 4U, hIDAT, hIHDR, 0}
}
という構造体配列に対しての初期化子リストになります。
*/
unsigned int test() {
return read_chunks[0].handler(0, 0, 0); //構造体に関数があるようにみえる
}
なお、Visual Studioであれば、マクロ展開される部分にマウスを持っていくと、マクロを展開した状態がポップアップされます
png_handle_result_code (*handler)(png_structrp, png_inforp, png_uint_32 length);
これは「png_handle_result_code型を返す関数」への関数ポインタ型のフィールドですね。
- フィールド名: handler
- 関数の戻り値: png_handle_result_code型
- 関数の第1引数: png_structrp型 で引数名は省略
- 関数の第2引数: png_inforp型 で引数名は省略
- 関数の第3引数: png_uint_32型 で引数名がlength
構造体のフィールドが関数ポインタ型であると、その関数ポインタは構造体に関数が定義されているように呼び出せます。 ただしC++のclassのメンバ関数のように暗黙のthisがないので自分自身を参照できるわけではないですね
# 20260510 0810 添付コードを単独でコンパイルできるように偽関数などを追加