What does an exclamation mark in array index do?
Asked Answered
Z

4

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?

Zee answered 13/9, 2016 at 13:42 Comment(0)
E
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...

Eluvium answered 13/9, 2016 at 13:45 Comment(4)
"You " + ["are", "are not"][!loggedIn()] + " logged in." ← an example of the same idea in JavaScript. Agreed icky, but not C's fault!Hirundine
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.Ramsey
@Hirundine 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"Cholecyst
@ThomasPadron-McCarthy C is like a kitten, C++ is more like a zoo. It's nice, in its own overwhelming way ;)Imbrication
I
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.

Imbrication answered 13/9, 2016 at 13:57 Comment(0)
P
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.

Pyjamas answered 13/9, 2016 at 13:45 Comment(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.Hyperbole
@Bathsheba: Fair point. I'll add a few words for completeness.Pyjamas
T
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.

Turbine answered 13/9, 2016 at 13:57 Comment(6)
By writing it like this you don't generate a branch instruction in your code, although the immediate purpose might not be obvious...Chow
@Chow We're writing code for human to be read, not just for computer. :)Turbine
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.Verbid
What I meant to say is that when the immediate purpose is not obvious one should make it obvious with comments, what @David Heyman saidChow
@Chow 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.Lakeishalakeland
For the readable version (ParameterWorkingIdx == 0 ? 1 : 0) clang uses the cmove instruction and does not branch (x86_64). gcc does.Igorot

© 2022 - 2024 — McMap. All rights reserved.