27

While perusing through my organization's source repository I came across this little gem:

RawParameterStorage[!ParameterWorkingIdx][ParameterDataOffset] = ...

Is this valid code? (It compiles) What does the exclamation mark here do?

An invert ~ operator might make sense, since it's commonly confused with the not ! operator in boolean expressions. However, it doesn't seem to make logical sense to impose the not ! operator on an array index. Any Thoughts?

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
Jim Fell
  • 13,750
  • 36
  • 127
  • 202

4 Answers4

43

!ParameterWorkingIdx Means ParameterWorkingIdx is 0, If it is, !ParameterWorkingIdx evaluates as true which might be implicitly converted to the indexer type (For example, 1 for integer indexer as in an array), otherwise, it evaluates as false.

  • If ParameterWorkingIdx == 0 then [!ParameterWorkingIdx] == [1].

  • If ParameterWorkingIdx != 0 then [!ParameterWorkingIdx] == [0].

It also depends on other stuff like:

  • The type of ParameterWorkingIdx.

  • overloading of ! operator by the type of ParameterWorkingIdx.

  • indexer overloading by the type of RawParameterStorage.

  • etc...

Tamir Vered
  • 10,187
  • 5
  • 45
  • 57
  • 12
    `"You " + ["are", "are not"][!loggedIn()] + " logged in."` ← an example of the same idea in JavaScript. Agreed icky, but not C's fault! – j6m8 Sep 13 '16 at 20:32
  • I think you need to remove the "different than" from the first sentence. In its current form it's the opposite of what you want to say. – CodesInChaos Sep 13 '16 at 20:36
  • 1
    @j6m8 actually that doesn't work as in JS, properties are cast to strings and booleans end up as `"true"`/`"false"` then. So either use `"You "+["are not", "are"][+loggedIn()]+" logged in"` or `"You "+{false:"are not", true:"are"}[loggedIn()]+" logged in"` – Bergi Sep 13 '16 at 21:17
  • 3
    @ThomasPadron-McCarthy C is like a kitten, C++ is more like a zoo. It's nice, in its own overwhelming way ;) – Quentin Sep 14 '16 at 08:34
19

Taking a bit of a guess here, but that looks like a double-buffer pattern. ParameterWorkingIdx would flip-flop between 0 and 1 (probably with ParameterWorkingIdx = !ParameterWorkingIdx;).

Then, at any time, RawParameterStorage[ParameterWorkingIdx] would be the current buffer, and RawParameterStorage[!ParameterWorkingIdx] would be the previous buffer.

Tamir Vered
  • 10,187
  • 5
  • 45
  • 57
Quentin
  • 62,093
  • 7
  • 131
  • 191
8

it doesn't seem to make logical sense to impose the not ! operator on an array index

It might: all it does here is convert zero to one, and any other number to zero.

We can infer from this code that RawParameterStorage probably has two elements at the top level.

P. S. Here, I assume that RawParameterStorage is an array (as you say it is). Furthermore, I assume that ParameterWorkingIdx is an integer (as its name implies). If, for example, either is a class with overloaded operators than the semantics could be completely different.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • 2
    UV'd but this does assume that `ParameterWorkingIdx` is not an instance of a class with an overloaded ! operator. The OP would be wise to check that. – Bathsheba Sep 13 '16 at 13:47
  • @Bathsheba: Fair point. I'll add a few words for completeness. – NPE Sep 13 '16 at 13:48
3

Is this valid code?

Yes it is. Suppose ParameterWorkingIdx to be an int, for !ParameterWorkingIdx, when used with operators !, it'll be contextually convertible to bool,

The value zero (for integral, floating-point, and unscoped enumeration) and the null pointer and the null pointer-to-member values become false. All other values become true.

Then integral promoted to be used as the array index.

the type bool can be converted to int with the value false becoming ​0​ and true becoming 1.

So !ParameterWorkingIdx is equivalent with ParameterWorkingIdx == 0 ? 1 : 0, which is much more clear IMO.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • By writing it like this you don't generate a branch instruction in your code, although the immediate purpose might not be obvious... – XapaJIaMnu Sep 13 '16 at 14:47
  • @XapaJIaMnu We're writing code for human to be read, not just for computer. :) – songyuanyao Sep 13 '16 at 14:56
  • 2
    If performance of this chunk is important enough that avoiding the branch instruction is helpful, just add the ternary-conditional version as a comment. Or a plain-English version of the same. – Vivian Sep 13 '16 at 15:01
  • What I meant to say is that when the immediate purpose is not obvious one should make it obvious with comments, what @David Heyman said – XapaJIaMnu Sep 13 '16 at 15:07
  • @XapaJIaMnu In such cases, clear and unambiguous documentation explaining why the special kind of language sorcery had to be invoked should've been placed in the source code. – code_dredd Sep 14 '16 at 05:45
  • For the readable version (`ParameterWorkingIdx == 0 ? 1 : 0`) clang uses the `cmove` instruction and does not branch (x86_64). gcc does. – tamas.kenez Sep 27 '16 at 06:41