Author Topic: Small C++ Test.  (Read 18331 times)

ficedula

  • *
  • Posts: 2178
    • View Profile
    • http://www.ficedula.co.uk
Small C++ Test.
« Reply #25 on: 2006-04-29 14:45:19 »
Quote
Incidentally, do you think that programmer would have coded the same way after taking this test?


In my mind, there are two kinds of programmers: The sort that have to be hit by a brick in order to remember something, and the sort that have to be hit by a big brick.

The first impression many programmers have on seeing information such as that presented in the test (I don't exclude myself from this) is "Whoa, cool! I'll be a good little programmer and when I use it I'll make sure to test that it does what I want it to!". And then go away satisfied that they've got the point - test your code!

Really, of course, the point is "Don't fucking do this!", but the innate coolness of an Interesting Feature prevents people from getting that. I know generally people learn better when they find things out themselves rather than being just taught, but that seems dangerous with programmers - most programmers (again, probably including myself) think they're better than they really are ;)  I like to spell it out, preferably in big comments in the code/source repository/office memo:

USE THIS FEATURE AND I WILL HUNT YOU DOWN AND HURT YOU

(Once that's understood, sure, it's fun to have a discussion about these wacky features. I just like to get the line about hurting people in first.)

L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Small C++ Test.
« Reply #26 on: 2006-04-29 14:52:31 »
I put up a disclaimer to thwart the evil-doers who want to try to use these tricks.


L. Spiro

Qhimm

  • Founder
  • *
  • Posts: 1996
    • View Profile
    • Qhimm.com
Small C++ Test.
« Reply #27 on: 2006-05-01 14:08:09 »
Wah, I got here late. Let me just try the questions without reading the thread first (sorry if this looks terribly stupid if you discussed it to death already).

1. J is undefined, dependant on the compiler implementation. The standard does not specify exactly when the post-increment is performed during the expression evaluation; it may be done immediately after the retrieval of the value, or some time later up until the expression is "finished" (IIRC compilers are allowed to delay it all the way up to the ';', the end of the statement). Therefore, J can be either 60 or 61, depending on when the post-increment is applied.

2. I is 1. Had I initially been set to 1 instead of 0, there would be ambiguity for the same reason as above, though compiler writers would be likely to implement the compiler to apply the post-increment within the numerical expression evaluation, before moving on to the next part of the boolean expression. Why is this significant? I don't know, it's just ugly because of the high risk of ambiguity.

3. J is probably 2, but I think the standard doesn't guarantee that (since again it uses a variable which is also post-incremented within the same expression, and the order of events is not clearly defined). It is likely to work though, due to how boolean expressions are typically handled by compilers.

4. I'd say that the result is 1, for the same reason that (((int *)2) + 1) equals (int *)6. When offsetting pointers with integers, the integers are scaled by the pointer type size; in this case, an int, by 4 (bytes). I haven't tested it on actual compilers, but I imagine the same mechanics apply when subtracting two pointers. One significance of this kind of pointer arithmetic is that array indexing and pointer math becomes one and the same, e.g. array[5] = *(array + 5).

5. Ooh, nice. I'd have to say this is undefined as well. The post-increment can be applied within the right-hand side expression (resulting in I = 2), or it can be applied after the entire assignment expression as a whole has been evaluated (resulting in I = 3).

6. Undefined. Again, the order of evaluation/application is not specified, and additionally I haven't seen any specification of which side of comparison operators are evaluated first. If we make the assumption that the right-hand side is evaluated first, then J is 1. If the left-hand side is evaluated first, J is 0. I don't think the standard dictates either way.

7. Specify according to what? As I said I don't think the standard specifies the order and timing of post-increments, or even the order of evaluation of this kind of expression. Those indexings just become a (I++)*sizeof(structitem) + (++I)*sizeof(anotherstructitem) + offsetof(iInt), and added to the address of g_mMyStructArray, which again there's no specific order of evaluation defined. But fine, here's a best-effort attempt to guess how a current compiler would do it, if it followed the "increment as soon as possible" approach. (I++ == 0) evaluates to true, and I is incremented (1), then I's value (1) is taken, after which it is incremented again (2). g_mMyStructArray is indexed (2), I is incremented (3), I is incremented again (4) and used to index sAnotherStruct. So [2][4] = 1. Note again, however, that the compiler is well within its rights to optimize code by moving around a) where post-increments are applied, and b) the order of evaluation to calculate a final pointer offset. The only case where you can force the evaluation order of the left-hand side here is if you're using overloaded [] operators, forcing a left-to-right evaluation. Even assuming this would be the case though, the compiler is still free to hold up the post-increments until the end of the statement, resulting in
  • [1] = 0 (quite a different result). The only assumption I've made here is that the right-hand side of an assignment expression is typically (possibly even definedly) done first.



Now to read through the discussion, I expect some goodies.  8)