3

Consider the following code: argv[1][2]

How does C++ handle the index evaluation? For example left to right: [1] is evaluated before [2], right to left: [2] is evaluated before [1] or does this depend on the compiler used?

Thijmen
  • 374
  • 2
  • 14
  • Depends upon the compiler – john Sep 14 '18 at 12:29
  • @john how can this be different than `*(*(argv + 1) + 2)`? Here we have strict order of evaluation caused by parentheses – Fureeish Sep 14 '18 at 12:30
  • Grouping is not order of evaluation, `1` could be evaluated before `2` or the other way around. Obviously in this case it makes no difference, but if the sub-expressions had side effects then the order of evaluation could matter, and the behaviour would be implementation dependent. – john Sep 14 '18 at 12:31
  • But how can one know how to offset `*(argv + 1)` before actually getting that value? – Fureeish Sep 14 '18 at 12:32
  • @Fureeish Consider `*(*(argv + f()) + g())` it's not specified whether `f` or `g` will be called first. That's what's meant by order of evaluation. There's no doubt how the return values of `f` and `g` will be used, but which is called first is unspecified. – john Sep 14 '18 at 12:34
  • This is an entirely different thing. My question is not about "when the `2` and `1` are evaluated (if they must be)". My question is how exactly the example OP provided can be compiler dependant. I'm pretty sure you mixed the order of argument evaluation with the order of execution **after** they are evaluated. EDIT: **aschepler**s answer seems to confirm my thought process – Fureeish Sep 14 '18 at 12:37
  • 1
    @john Note C++17 changed the rules so that `f()` must be called before `g()`: see my answer. – aschepler Sep 14 '18 at 12:38
  • @Fureeish I don't think I misinterpreted the question. But you are correct the inner + must be evaluated before the outer +. Apparently my answer changes in C++17 anyway. – john Sep 14 '18 at 12:42

5 Answers5

10

Strictly speaking, there are a number of evaluations going on in argv[1][2] (which is equivalent to (argv[1])[2])

  1. Evaluate argv
  2. Evaluate 1
  3. Evaluate 2
  4. Evaluate argv[1]
  5. Evaluate argv[1][2]

An operator expression can't really be evaluated without knowing what its operands' values are, so #1 and #2 must happen before #4, and #3 and #4 must happen before #5.

Of course, "evaluate 1" doesn't have much meaning since it's just a literal known value. But if the expression were something like argv[f1()][f2()] instead, then the order of subexpression evaluations can matter.

In versions of C++ up to C++14, it is unspecified in argv[f1()][f2()] whether f1() or f2() is called first. C++17 introduced a lot of additional guarantees on the order of subexpressions, including a rule for array subscripting: in A[B], all evaluations and side effects for subexpression A now happen before all evaluations and side effects of subexpression B. So C++17 guarantees in this case that f1() will be called before f2().

aschepler
  • 70,891
  • 9
  • 107
  • 161
2

For any array or pointer a and index i, the expression a[i] is exactly equal to *(a + i). In short, all array indexing is "simple" pointer arithmetic.

For an array of arrays (or array of pointers) like argv normally is, then argv[i][j] is equal to (argv[i])[j] which is equal to (*(argv + i))[j] which is equal to (*(argv + i)) + j).

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
1

It is converted exactly to: *(*(argv + 1) + 2). You might want to learn about pointer arithmetic

Fureeish
  • 12,533
  • 4
  • 32
  • 62
1

It's (argv[x])[y]. If argv is and array of pointers to C-strings (an argument to the main() for instance). Then the first index picks the string and the second argument — a character in the string.

bobah
  • 18,364
  • 2
  • 37
  • 70
1

argv[1][2] is grouped strictly as ((argv[1])[2]).

So the expression is equivalent to *(*(argv + 1) + 2), which is a char type.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483