我正在查看IDE中包含的math.h标头。我看到以下代码是我不理解的语法。这是基本的东西,但有人可以向我解释这是如何工作的吗?
#define isgreater(x,y) \
(__extension__ ({__typeof__(x) __x = (x); __typeof__(y) __y = (y); \
!isunordered(__x,__y) && (__x > __y);}))
例如,当您开始使用双下划线时,它会做什么,例如:__typeof
是否允许不确定的尺寸?所以这个宏可以采用不同大小的值吗?
斜线只是跨越源中的换行符吗?
__extension__
做了什么?
感谢
答案 0 :(得分:8)
您正在使用一些编译器扩展:
__typeof__
是一个GCC扩展,它允许您获取变量的类型(并在变量声明中使用它);它存在,以便宏可以处理任何类型x
和y
。({ ... })
转换为表达式,该表达式计算为其中最后一个语句的值;这允许您在此块中声明变量,这是为了避免两次评估两个操作数x
和y
。 x
和y
的结果(可能类似i++
,您不想要评估两次)存储在两个临时变量__x
和{ {1}}然后使用这两个临时变量而不是__y
和x
来避免双重评估。y
是一个扩展程序,可以抑制您使用上述扩展程序时发出的警告。是的,__extension__
只是使宏跨度的定义多行(\
将行连接在一起,并且在编译过程中很早就完成了,甚至在查看宏和预处理器定义之前在)。
这个严峻的要点是避免两次评估\
和x
。如果你做了
y
你没有使用这个技巧,你得到了
bool g = isgreater(x++, y++);
这会导致bool g = !isunordered(x++, y++) && (x++ > y++);
和x
每次增加两次,而不是像您预期的那样增加一次。相反,通过这个技巧,你可以获得类似的东西(使用更好的临时变量名称)
y
(如果int tmpx = x++;
int tmpy = y++;
bool g = !isunordered(tmpx, tmpy) && (tmpx > tmpy);
和x
是整数)这是正确的,并避免双增量。这也适用于其他事情,例如函数调用:
y
如果没有技巧,你最终会发射14枚导弹而不是7枚,这将是灾难性的。
答案 1 :(得分:3)
重新格式化定义可能对您有所帮助
#define isgreater(x,y) \
( \
__extension__ ( \
{ \
__typeof__(x) __x = (x); \
__typeof__(y) __y = (y); \
!isunordered(__x,__y) && (__x > __y); \
} \
) \
)
__extension__
标记使用gcc扩展到标准ANSI C的代码。在这种情况下的扩展是__typeof__
运算符,它在编译时提供变量的类型,并用于声明{ {1}}和__x
与__y
和x
的类型相同。然后继续检查这对值是否有序(y
是数学库函数)并且isunordered
大于__x
。