三元运算是否在编译时进行?
Are ternary operations carried out at compile-time?
我正在用 C 从头开始制作一个基于位板的国际象棋引擎。移动生成过程对时间特别敏感。目前,我的代码是这样的:
void generate_moves(Position *p, Colour side, Move *list) {
if(side == WHITE) {
Bitboard b1 = p->piece_bitboards[BLACK_KNIGHT];
Bitboard top_rank_mask = MASK_RANK[RANK8];
...
} else {
Bitboard b1 = p->piece_bitboards[WHITE_KNIGHT];
Bitboard top_rank_mask = MASK_RANK[RANK1];
...
}
}
以及其他数百行代码,这些代码要么是黑白镜像,要么是相同的。但是,这对我来说似乎容易出错并且令人困惑。
所以将在每个分叉处用三元运算符替换大的 if-else 以提高可读性:
void generate_moves(Position *p, Colour side, Move *list) {
Bitboard b1 = p->piece_bitboards[side == WHITE ? WHITE_KNIGHT :
BLACK_KNIGHT];
Bitboard top_rank_mask = MASK_RANK[side == WHITE ? RANK8 : RANK1];
...
}
有相似的表现吗?所有三元运算符都依赖于变量端,它只能假定常量值 WHITE 或 BLACK。
除非禁用优化,否则任何中等质量的编译器都会同样对待这两个代码序列。
第二个序列名义上有两个或多个测试,但编译器应该识别重复的表达式以及它不能从一个语句更改为下一个语句的事实,因为其中的操作数不受先前任何内容的影响语句(Bitboard b1 = p->piece_bitboards[side == WHITE ? WHITE_KNIGHT :
BLACK_KNIGHT];
)。 (大概 WHITE
是一个常数。)即使是中等质量的编译器也希望进行这种优化。
至于选择(if
序列中的两个块之一或另一种情况下的三元操作数)是否会在编译时进行,除非编译器知道side
的值。由于 side
是一个函数参数,编译器不能仅从函数的源代码中知道它的值。如果编译器可以看到调用函数的位置并且为 side
传递的参数是常量表达式或者可以由编译器以其他方式推导出来,它就可以知道它的值。例如,如果调用代码包含两个序列,其中一个为 WHITE
调用 generate_moves
,另一个为 BLACK
调用 generate_moves
,则编译器可能会为 generate_moves
生成内联代码,其中在每种情况下都优化了选择。
执行此操作的情况不太清楚,更多取决于编译器和其他代码的属性,您没有显示。
与您确定的条件选择相比,此类代码的性能可能更受其他因素的影响。
我正在用 C 从头开始制作一个基于位板的国际象棋引擎。移动生成过程对时间特别敏感。目前,我的代码是这样的:
void generate_moves(Position *p, Colour side, Move *list) {
if(side == WHITE) {
Bitboard b1 = p->piece_bitboards[BLACK_KNIGHT];
Bitboard top_rank_mask = MASK_RANK[RANK8];
...
} else {
Bitboard b1 = p->piece_bitboards[WHITE_KNIGHT];
Bitboard top_rank_mask = MASK_RANK[RANK1];
...
}
}
以及其他数百行代码,这些代码要么是黑白镜像,要么是相同的。但是,这对我来说似乎容易出错并且令人困惑。
所以将在每个分叉处用三元运算符替换大的 if-else 以提高可读性:
void generate_moves(Position *p, Colour side, Move *list) {
Bitboard b1 = p->piece_bitboards[side == WHITE ? WHITE_KNIGHT :
BLACK_KNIGHT];
Bitboard top_rank_mask = MASK_RANK[side == WHITE ? RANK8 : RANK1];
...
}
有相似的表现吗?所有三元运算符都依赖于变量端,它只能假定常量值 WHITE 或 BLACK。
除非禁用优化,否则任何中等质量的编译器都会同样对待这两个代码序列。
第二个序列名义上有两个或多个测试,但编译器应该识别重复的表达式以及它不能从一个语句更改为下一个语句的事实,因为其中的操作数不受先前任何内容的影响语句(Bitboard b1 = p->piece_bitboards[side == WHITE ? WHITE_KNIGHT :
BLACK_KNIGHT];
)。 (大概 WHITE
是一个常数。)即使是中等质量的编译器也希望进行这种优化。
至于选择(if
序列中的两个块之一或另一种情况下的三元操作数)是否会在编译时进行,除非编译器知道side
的值。由于 side
是一个函数参数,编译器不能仅从函数的源代码中知道它的值。如果编译器可以看到调用函数的位置并且为 side
传递的参数是常量表达式或者可以由编译器以其他方式推导出来,它就可以知道它的值。例如,如果调用代码包含两个序列,其中一个为 WHITE
调用 generate_moves
,另一个为 BLACK
调用 generate_moves
,则编译器可能会为 generate_moves
生成内联代码,其中在每种情况下都优化了选择。
执行此操作的情况不太清楚,更多取决于编译器和其他代码的属性,您没有显示。
与您确定的条件选择相比,此类代码的性能可能更受其他因素的影响。