【问题标题】:Are ternary operations carried out at compile-time?三元运算是在编译时执行的吗?
【发布时间】:2019-10-11 17:44:13
【问题描述】:

我正在用 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。

【问题讨论】:

  • 它们不可能在编译时完成,因为它们依赖于运行时变量。
  • 你已经用数百个分支替换了一个分支。自然,它应该以(性能)为代价。作为旁注,我想说似乎没有任何充分的理由对这个问题投反对票。没关系。

标签: c performance ternary-operator


【解决方案1】:

任何中等质量的编译器都将这两个代码序列视为相同,除非优化被禁用。

第二个序列名义上具有两个或多个测试,但是编译器应该识别重复的表达式以及它不能从一个语句更改为下一个语句的事实,因为其中的操作数不受前一个语句中的任何内容的影响( s) (Bitboard b1 = p->piece_bitboards[side == WHITE ? WHITE_KNIGHT : BLACK_KNIGHT];)。 (大概WHITE 是一个常数。)即使是中等质量的编译器也需要这种优化。

至于(if 序列中的两个块中的一个或另一种情况下的三元操作数)是否将在编译时进行选择,除非编译器知道 @987654324 的值,否则不会发生这种情况@。由于side是一个函数参数,编译器不能仅从函数的源代码中知道它的值。如果编译器可以看到函数被调用的位置并且为side 传递的参数是一个常量表达式或者可以由编译器以其他方式推断,它就可以知道它的值。例如,如果调用代码包含两个序列,其中一个为WHITE 调用generate_moves,另一个为BLACK 调用generate_moves,编译器可能会为generate_moves 生成内联代码在每种情况下,选择都得到了优化。

执行此操作的情况不太清楚,更多地取决于编译器和其他代码的属性,您没有显示。

这样的代码的性能可能更多地受到其他因素的影响,而不是您确定的条件选择。

【讨论】:

    猜你喜欢
    • 2017-12-06
    • 2017-05-12
    • 1970-01-01
    • 2015-09-21
    • 2018-04-26
    • 1970-01-01
    • 1970-01-01
    • 2017-08-26
    • 2022-01-17
    相关资源
    最近更新 更多