【发布时间】:2019-06-15 11:22:36
【问题描述】:
我阅读了这个来源 (https://github.com/lattera/glibc/blob/master/stdio-common/vfprintf.c) 并发现了一些我不完全理解的有趣的行:
#ifdef SHARED
/* 'int' is enough and it saves some space on 64 bit systems. */
# define JUMP_TABLE_TYPE const int
# define JUMP_TABLE_BASE_LABEL do_form_unknown
# define REF(Name) &&do_##Name - &&JUMP_TABLE_BASE_LABEL
# define JUMP(ChExpr, table) \
do \
{ \
int offset; \
void *ptr; \
spec = (ChExpr); \
offset = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \
: table[CHAR_CLASS (spec)]; \
ptr = &&JUMP_TABLE_BASE_LABEL + offset; \
goto *ptr; \
} \
while (0)
...
#define STEP0_3_TABLE \
/* Step 0: at the beginning. */ \
static JUMP_TABLE_TYPE step0_jumps[30] = \
{ \
REF (form_unknown), \
REF (flag_space), /* for ' ' */ \
REF (flag_plus), /* for '+' */ \
REF (flag_minus), /* for '-' */ \
REF (flag_hash), /* for '<hash>' */ \
REF (flag_zero), /* for '0' */ \
REF (flag_quote), /* for '\'' */ \
REF (width_asterics), /* for '*' */ \
REF (width), /* for '1'...'9' */ \
REF (precision), /* for '.' */ \
REF (mod_half), /* for 'h' */ \
...
我写了一个简单的例子,并理解这一行 &&do_##Name 将 do_##Name 转换为指向 void 的指针。但我不明白在这种情况下指针算法是如何工作的:#define REF(Name) &&do_##Name - &&JUMP_TABLE_BASE_LABEL 有人可以写简单的解释吗?或者写一些指向 Internet 资源的链接,我可以在其中阅读有关此技术的信息。
【问题讨论】:
-
处理器对C语言和指针一无所知
-
您可能想看看预处理的 C 代码。使用 GCC,您可以通过
cpp file.c看到它。 -
这里使用 gcc goto 扩展 - 这不是很标准的 C
-
@P__J__ 和
void *上的指针运算,另一个 gcc 扩展。 -
@melpomene 确实如此。但它是 gcc glibc :)。无论如何,这是一个非常有效的 gcc 代码,但不是我建议学习的代码。它被写成尽可能高效。当你获得更多经验时再回来
标签: c gcc goto pointer-arithmetic