作为命令的三元操作符

Ternary operator as a command?

本文关键字:三元 操作符 命令      更新时间:2023-10-16

nanodns的源代码中,有一个非典型的三元操作符的使用,试图减少代码的大小:

/* If the incoming packet has an AR record (such as in an EDNS request),
 * mark the reply as "NOT IMPLEMENTED"; using a?b:c form to save one byte*/
q[11]?q[3]|=4:1;

这一行的作用并不明显。乍一看,它看起来像是在给两个数组元素中的一个赋值,但事实并非如此。相反,它似乎要么是一个数组元素,要么什么都不做(运行"命令"1)。

它看起来应该是这行代码的替换(它确实长了一个字节):

if(q[11])q[3]|=4;

对应的文字是:

if (q[11])
  q[3]|=4;
else
  1;

三元操作符通常用作表达式的一部分,因此将其用作独立命令似乎有些奇怪。加上看起来不合适的1,这一行几乎可以称得上是混淆的代码。

我做了一个快速的测试,能够编译和运行一个C(++)程序与数据常量作为"命令",如void main() {0; 'a'; "foobar"; false;}。这似乎是一种nop命令,但我找不到任何关于这种用法的信息(谷歌不太支持这种类型的搜索查询)。

谁能确切地解释一下它是什么以及它是如何工作的?

在C和c++中,只要把;放在末尾,任何表达式都可以构成一个语句。

另一个例子是表达式x = 5可以做成一个语句:x = 5;。希望你同意这是个好主意。

如果试图"禁止"某些表达式子集后面出现;,这将不必要地使语言复杂化。这个代码不是很有用,但它是合法的。

请注意,您链接到的代码非常糟糕,并且是由一个非常糟糕的程序员编写的。特别是,语句

"在小型C程序中定义重用表达式是常见的做法使代码更小"

是完整的b***s***。这句话就是事情开始变得非常糟糕的地方。

源代码的大小与编译器可执行文件的大小没有关系,与可执行文件的内存消耗也没有关系,与程序性能也没有关系。它唯一影响的是程序员计算机上源代码文件的大小,用字节表示

除非你是在80年代中期的8086计算机上编程,硬盘空间非常有限,否则你永远不需要"减少代码的大小"。相反,编写可读的代码。

话虽如此,由于q是一个字符数组,因此您链接的代码相当于

if(q[11])
{
  (int)(q[3] |= 4);
}
else
{
  1;
}

其中1是一个没有副作用的语句,它将被优化掉。它被放在那里只是因为?:运算符需要第三个运算符。

if语句和?:操作符之间的唯一区别是微妙的:?:隐式地平衡了第二个和第三个操作数之间的类型。

为了提高可读性和生成自文档代码,应该将代码重写为类似

的内容。
if (q[AR_INDEX] != 0)
{
  q[REPLY_INDEX] |= NOT_IMPLEMENTED;
}

作为旁注,这里有一个错误:q[2]|=128;q是char类型,它具有实现定义的签名,因此这一行可能是灾难性的。核心问题是,您永远不应该将char类型用于位操作或任何形式的算术,这是典型的初学者错误。必须替换为uint8_tunsigned char