Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ternary operator as a command?

In the source-code for nanodns, there is an atypical use of the ternary operator in an attempt to reduce the size of the code:

/* 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;

It’s not obvious what this line does. At first glance, it looks like it is assigning a value to one of two array elements, but it is not. Rather, it seems to be either or’ing an array element, or else, doing nothing (running the “command” 1).

It looks like it is supposed to be a replacement for this line of code (which is indeed one byte longer):

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

The literal equivalent would be this:

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

The ternary operator is typically used as part of an expression, so seeing it used as a standalone command seems odd. Coupled with the seemingly out of place 1, this line almost qualifies as obfuscated code.

I did a quick test and was able to compile and run a C(++) program with data constants as “command”, such as void main() {0; 'a'; "foobar"; false;}. It seems to be a sort of nop command, but I cannot find any information about such usage—Google isn’t very amenable to this type of search query).

Can anyone explain exactly what it is and how it works?

like image 463
Synetech Avatar asked Jul 15 '26 07:07

Synetech


2 Answers

In C and C++ any expression can be made into a statement by putting ; at the end.

Another example is that the expression x = 5 can be made into a statement: x = 5; . Hopefully you agree that this is a good idea.

It would needlessly complicate the language to try and "ban" some subset of expressions from having ; come after them. This code isn't very useful but it is legal.

like image 67
M.M Avatar answered Jul 18 '26 14:07

M.M


Please note that the code you linked to is awful and written by a really bad programmer. Particularly, the statement

"It is common practice in tiny C programs to define reused expressions to make the code smaller"

is complete b***s***. That statement is where things started to go terribly wrong.

The size of the source code has no relation to the size of the compiler executable, nor any relation to that executable's memory consumption, nor any relation to program performance. The only thing it affects is the size of the source code files on the programmers computer, expressed in bytes.

Unless you are programming on some 8086 computer from mid-80s with very limited hard drive space, you never need to "reduce the size of the code". Instead, write readable code.

That being said, since q is an array of characters , the code you linked is equivalent to

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

Where 1 is a statement with no side effect, it will get optimized away. It was only placed there because the ?: operator demands a 3rd operator.

The only difference between if statements and the ?: operator is subtle: the ?: implicitly balances the type between the 2nd and 3rd operand.

To increase readability and produce self-documenting code, the code should get rewritten to something like

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

As a side note, there is a bug here: q[2]|=128;. q is of type char, which has implementation-defined signedness, so this line is potentially disastrous. The core problem is that you should never use the char type for bit-wise operations or any form of arithmetic, which is a classic beginner mistake. It must be replaced with uint8_t or unsigned char.

like image 36
Lundin Avatar answered Jul 18 '26 14:07

Lundin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!