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

L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Small C++ Test.
« on: 2006-04-25 15:52:50 »
Not too hard, but a good tester of just how intimate you are with the language.

Obviously the solutions to all of these problems can be found by simply compiling the code and viewing the results, but that defeats the purpose entirely.

Try to see how many of these you know right off the top of your head.

These are all my own original questions, by the way.


DISCLAIMER: THESE QUESTIONS ARE NOT INTENDED TO BE EXAMPLES OF QUALITY CODE.  IN FACT, THE ANSWERS TO MOST THESE QUESTIONS DEMONSTRATE EXACTLY WHY YOU SHOULD NOT CODE THIS WAY.



1:
Code: [Select]
int I = 30;
int J = ((I++) + I++);

What is the value of J?

2:
Code: [Select]
int I = 0;
int J = 0;
if ( I++ == 1 && I++ == 2 ) { J = 1; }

What is the value of I after this entire code segment is processed?  Why is this significant?

3:
Code: [Select]
int I = 0;
int J = ( I++ == 1 || ++I == 1 ) ? ++I : I++;

What is the value of J?

4:
Code: [Select]
(int *)6 - (int *)2
What is the result of this expression and why?





L. Spiro

Aaron

  • *
  • Posts: 2818
    • View Profile
    • http://aaron-kelley.net/
Small C++ Test.
« Reply #1 on: 2006-04-25 18:25:32 »
Spoiler: show
Mmm...  So I answered them all and then checked them before posting.  :-P  I got them all except 4.

1.
I was expecting 61 (30 + 31) but VS2005 gave me 60.
It must be taking some shortcut?
I was so expecting 61 that I tried it on a different compiler (Metrowerks CodeWarrior) and then I got 61 as the result.

2.
Value of I = 1
(It short-circuited out of the check because the one of the left was false)

3.
Value of J = 2

4.
Silly pointer math.
I'm at a loss to explain this one, it's a C++ism that I'm not familiar with.

dziugo

  • *
  • Posts: 1470
    • View Profile
    • A new copy of FF7 thanks to Salk. Pack (zip/rar/etc) your saved game before sending it to me.
Small C++ Test.
« Reply #2 on: 2006-04-25 19:50:13 »
I remember when I was discovering the power of pre- and post- incrementation. It took me a while before I realized that you can rewrite the line moving all the pre-incr. before the executed line and all the post-incr. after the line. That's why Aaron's reply to the 1st one surprised me...

And the 4th question doesn't have one answer. It depends on the system you run it on (
Spoiler: show
size of integer
).

dziugo

Aaron

  • *
  • Posts: 2818
    • View Profile
    • http://aaron-kelley.net/
Small C++ Test.
« Reply #3 on: 2006-04-25 21:05:55 »
Spoiler: show
On that one...

I see how subtracting a number from a pointer would be different, depending on the size of an integer (or whatever data type).  For example...

(int*)10 - 2;
is kind of like
10 - (2 * sizeof(int));

I guess I haven't used pointer subtraction like this before, though, it's giving me a result of 1 (whether I am working in 32-bit 0x00000001 or 64-bit 0x0000000000000001) and I don't really know why.  :-P

L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Small C++ Test.
« Reply #4 on: 2006-04-26 01:48:15 »
Number 4 is the main one that so far no one, including my boss (7-year Ubisoft employee), has gotten.
It simply never happens in real coding.
But for the sake of simplicity let’s assume a standard 32-bit integer is being used.


According to the actual ANSI C specifications, Aaron, your CodeWarrior compiler is wrong.



5:
Code: [Select]
int I = 2;
I = I++;

What is the value of I?

6:
Code: [Select]
int I = 5;
int J = 0;
if ( I++ == ++I ) { J = 1; }

What is the value of J and why?



L. Spiro

Sukaeto

  • *
  • Posts: 570
    • View Profile
    • Sukaeto's web server
Small C++ Test.
« Reply #5 on: 2006-04-26 02:37:57 »
Wow, that's some REALLY bad code!  Anyway, I'll take a guess at them and then see what GCC produces . . .

Spoiler: show

1. I'm thinking it'll be 61 . . . this, though, might be one of those things that depends on the compiler (could end up being 62).  Even though i++ is *supposed* to be POST increment.

2.  Well, either way, I will be 2.  Now, whether or not J is assigned 1 again probably depends on the compiler.  Even though technically it SHOULDN'T be.

3.  Oh, this is disgusting . . . either it'll be 3 or 2.  It's *supposed* to be 2, though.

4. My god . . . I would imagine this thing would result in some kind of a bus error depending on its context.  I . . . don't even know what to say about this . . . All I know is, if I saw anyone seriously writing code like this I would smack them.  HARD.

5.  Should be 3, either way.

6.  Holy shitsticks, batman!  Um . . . geez.  I'm gonna go with . . . 0 on  this one.  What *probably* should be happening there is a comparison of 5 to 7 (which are of course not equal).


                        ------------------EDIT------------------

Here's what GCC/G++ produced:

Spoiler: show

1. Both produced 60.

2. Both produced 1.  You know why?  Short-circuit evaluation.  I realized this as soon as I saw the answer.  Silly me for thinking 2 above.

3. Both produced 2.


4. g++:  couldn't get this to compile.  I tried a variety of things.
With gcc I used this code:

Code: [Select]
#include <stdio.h>

int main() {
int *p;
p = (int *)6 - (int *)2;

printf("%d", &p);
return 0;
} // end int main()


Spoiler: show
and got a bullshit value.  So somehow, the app could actually de-reference that pointer and give me the "value" in the address


I changed the
Code: [Select]
printf("%d", &p); to
Code: [Select]
printf("%d", p);
Spoiler: show
and got a 1 . . . go figure.  I really have no fucking clue where that came from.  If I had to guess, I'd say it was printing the value in "words" and since the address 4 is "word 1" on an x86, this is what it gave me.


Remember kids:  DON'T TRY THIS AT HOME!!

Spoiler: show
5. Both of them produced 2.  Again, silly me.  This one VERY MUCH depends on the compiler writer.  Should the assignment of I happen *AFTER* the ++ or before it.  On one hand, I could get assigned 2 and THEN incremented.  On the *OTHER* hand, the 2 could be stored, I incremented and THEN I assigned 2.  There is a good saying for anyone who writes code like this:  "You get what you deserve."

6. Both of them produced 0.

The SaiNt

  • *
  • Posts: 1300
    • View Profile
Small C++ Test.
« Reply #6 on: 2006-04-26 03:53:57 »
No. 4
Spoiler: show

(int*) 6 returns 6
(int*) 2 returns 2

(int*)6 - (int*) 2
is really
(6 - 2) / sizeof(integer)
returning 1
due to the pointer arithmetic involved.

So if you did (int*)10 - (int*)2 you would get 2. [( 10 - 8 ) / 4]

In case you're interested, most compilers will implement it as a double shift right instead of a divide by 4.

ye-roon

  • *
  • Posts: 449
    • View Profile
Small C++ Test.
« Reply #7 on: 2006-04-26 06:17:58 »
Quote from: The SaiNt

Spoiler: show
[( 10 - 8 ) / 4]


should be
Spoiler: show
[( 10 - 2 ) / 4] cause  10 - 8 = 2 and 2 / 4 = 1/2 or 0.5 and not the 2 you were saying. right?

odo324

  • *
  • Posts: 98
    • View Profile
    • http://www.mindscape.siteburg.com
Small C++ Test.
« Reply #8 on: 2006-04-26 06:34:57 »
Questons: 1 - 4
Spoiler: show

1. 60 - The int I doesn't increment until after the assignment is given.
2. 00 - For the same reason above.
3. 02 - Anyone who actually uses that should be shot ...then kicked ...then run over with a truck.
4. Pointer arithmetic? Wouldn't that depend on the compiler that’s used? Funny thing is: I don’t think other data types have this problem.


What might confuse the vets? (excluding the
Spoiler: show
rarely used prefix of ++
)

Questons: (4.5) - 6
Spoiler: show

4.5 32-bit? Nope, still too lazy to wip out that old txtbook.
5. 03 - Ooo, tricky. :wink:
6. 00 - If I is 1 above itself now or after? Ok?

L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Small C++ Test.
« Reply #9 on: 2006-04-26 07:59:06 »
Quote
What might confuse the vets?

Well your answer for #2 is incorrect, but its’s because you misread the actual question rather than lack of understanding the inner workings of the problem.



The SaiNt, you explain how the value is obtained, but the second part of the question is why?  What is the significance of the value that is returned from that expression?


7:
Code: [Select]
int I = 0;
g_mMyStructArray[I++].sAnotherStruct[++I].iInt = (I++ == 0) ? I++ : -1;

Specify which iInt (g_mMyStructArray[??].sAnotherStruct[??].iInt) will have its value assigned and why.


L. Spiro

mirex

  • *
  • Posts: 1645
    • View Profile
    • http://mirex.mypage.sk
Small C++ Test.
« Reply #10 on: 2006-04-26 08:47:46 »
Spoiler: show

1: 61
2: i = 1 because it jumps out of the comparison after first false argument
3: j = 2
4: no idea. it could be 1 because of sizeof( int ) = 4 in these days.
5: i = 3. i would say it gets assigned an afterwards increased.
6: no idea but i hope for god's sake that I is increased before comparison so J = 1
7: i refuse to continue !


my comment:
dumb constructions ! allways use parenthesis and readable form of formulaes to avoid misunderstanding and these kinds of questions !
I am a 6-year veteran ;) and I never use these constructs because they are leading only to misunderstandings, not to faster code. Easy code readability is important to me.  That's why such knowledge should not be important.


I have one for you too. What is result of the expression ? Is it int or float ?

 ( 1 < 2 ) ? 3 : 4.0

L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Small C++ Test.
« Reply #11 on: 2006-04-26 09:32:26 »
These questions are very clearly not intended to indicate superiority in coding style.
For very clear reasons, you want to avoid coding this way.
But the test is actually to ensure actual understanding of operator precedence and order of evaluation, as such knowledge is valuable in normal code we write.

For example, the key to #2 is
Spoiler: show
to understand the importance of short-circuit code, because it specifically allows the following to be safe:

Code: [Select]
if ( piPointerToInt != NULL && *piPointerToInt  == 3 ) { /* Do something. */ }

This is good coding practice if the people reading/writing the code understand this concept, while new coders may steer away from this, just from lack of understanding.


The key to #7 is
Spoiler: show
understanding completely the order of evaluation.
It is important to know whether the left or right side of assignment expressions is evaluated first, for a start.



#4 is intended
Spoiler: show
to awaken programmers to the fact that pointer subtraction actually exists, and that the result is an int (not a pointer of any kind) that represents the difference in indices between the two addresses, given the specified type.




Quote
I am a 6-year veteran  and I never use these constructs because they are leading only to misunderstandings

And you are absolutely correct in deciding not to use many of these constructions.
But knowledge is always important.




Quote
I have one for you too. What is result of the expression ? Is it int or float ?

( 1 < 2 ) ? 3 : 4.0

Spoiler: show

Coincidentally, I just wrote that part of my own programming language last night, so unfortunately I already covered this on my own too (but did forget to ask it).
It is luck that I have actually written a C compiler, and have been forced to examine the results of all the questions posted here, including this one.



IF THE CONDITIONAL EXPRESSION WAS NOT CONSTANT:
As per the ANSI C++ standard, both values will be promoted based off the same rules that are used when and int and a double are multiplied, added, subtracted, etc.
If either operand is a double, both are promoted to doubles.
If either are floats, both become floats.
If either is an unsigned long, both become unsigned longs.
If either is an unsigned int, both become unsigned ints.
Finally, if none of the above has yet been matched, both sides become regular ints.

This changes per compiler based on sizes of int, etc., and whether or not int64 is supported, but in all cases double takes the cake.

Thus, the result of the expression would be a double in this case, then cast to whatever type is being assigned by this expression.




BUT SINCE THE CONDITIONAL EXPRESSION IS CONSTANT (1 is always less than 2):
The result will be an int.  The conditional expression and the third operand (4.0) will be completely ignored, and the expression is exactly equivalent to just typing “3” in the code instead.



L. Spiro

mirex

  • *
  • Posts: 1645
    • View Profile
    • http://mirex.mypage.sk
Small C++ Test.
« Reply #12 on: 2006-04-26 10:16:43 »
to L.Spiro's answer:
Spoiler: show

Try checking it in your compiler. Mine (MSVC 2005) does think that 3.0 double is an answer. I have checked it with this kind of test:

void fn( double d ) {  printf( "double %0.3f", d );  }
void fn( int d )  {  printf( "int %i", d );  }

int _tmain(int argc, _TCHAR* argv[])
{
   fn( ( 1 < 2 ) ? 3 : 4.0 );
   return 0;
}

Result printed on screen was: "double 3.000"

L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Small C++ Test.
« Reply #13 on: 2006-04-26 10:47:53 »
Spoiler: show

I get the same result but it may be a Microsoft thing.
They might be choosing their overload based off the same promotion rules I explained before, because neither overload is specifically better than the other except by the precision of the type.

The ANSI C++ definition implies that the 3 should be the immediate return with no code produced, and that its type should be retained, but I would like to see what other compilers return.




L. Spiro

ficedula

  • *
  • Posts: 2178
    • View Profile
    • http://www.ficedula.co.uk
Small C++ Test.
« Reply #14 on: 2006-04-26 16:55:49 »
Actually, the answer to (1), (6) and (7) is: completely undefined. The compiler could return 42 every time, shoot your pet dog, or cause the computer to blow up: all would be valid responses according to the C++ specification.

Spoiler: show

So for (7), it would be completely valid to say that every single entry in the array will have its value assigned. Even if there were 10 million of them. Undefined behaviour means the compiler can do anything. Of course, a more useful answer would be to point that the code is not really valid according to the specification.

See: http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.15 for an explanation why.

Also, a key point for (4) that I'd want anybody playing who-understands-the-language-the-most games to bring up would be: what if 0x6 and 0x2 aren't actually valid values for pointers to integers? Since you never dereference them, obviously you aren't actually going to trigger a memory violation, but it's not an irrelevant point if you're going to introduce pointers. After all, technically the difference in indices between the two addresses could be "undefined" since on some systems, neither contains a value that could actually point to an integer. I suspect the specification doesn't actually cover this behaviour, however.

odo324

  • *
  • Posts: 98
    • View Profile
    • http://www.mindscape.siteburg.com
Small C++ Test.
« Reply #15 on: 2006-04-26 18:21:50 »
Quote from: L. Spiro
...your answer for #2 is incorrect.

Of course! {slaps forehead}
Spoiler: show
 I must have been looking at J. I=2 because I++ (in both forms) increments I before the next statement is occurred, regardless of how it's used.
Thanks for the heads up.
Edit:
Spoiler: show
Never mind. After finally compiling it, I think I'm the one who just short-circuited. LOL.
Cool experiment.


Quote from: L. Spiro
...very clearly not intended to indicate superiority in coding style.

Phew, lol. I was hesitant to say anything. :wink:

#7
Spoiler: show
...[0]...[1].iInt
This is because the first I is not incremented until after the statement is run (I think) and the second I is incremented immediately. The resulting value of I, after the entire statement, should be 2.


Quote from: ficedula
Actually, the answer to (1), (6) and (7) is: completely undefined.

Com'on! This is just for fun... :P I hope nobody (in their right mind) would actually use such statements.

dziugo

  • *
  • Posts: 1470
    • View Profile
    • A new copy of FF7 thanks to Salk. Pack (zip/rar/etc) your saved game before sending it to me.
Small C++ Test.
« Reply #16 on: 2006-04-26 18:36:55 »
The 7th one is... Weird... I thought that I got why it does it that way, but then I compiled something like:
Code: [Select]
int I = 0;
struct1[++I].struct2[++I].struct3[++I].struct4[++I].struct5[++I].iInt = 1;
And... See by yourself. I don't expect an answer with explanation :P

dziugo

ficedula

  • *
  • Posts: 2178
    • View Profile
    • http://www.ficedula.co.uk
Small C++ Test.
« Reply #17 on: 2006-04-26 21:53:20 »
Quote from: odo324

Quote from: ficedula
Actually, the answer to (1), (6) and (7) is: completely undefined.

Com'on! This is just for fun... :P I hope nobody (in their right mind) would actually use such statements.


Sure, just remember that what happens is totally compiler dependent
Spoiler: show
in situations like that: you can't even really guess what will happen when you run the code, because even different versions of the same compiler might do different things ... or, worst of all, the same compiler might do different things depending on when and where you use it...

RPGillespie

  • *
  • Posts: 427
    • View Profile
    • http://www.geocities.com/rpgillespie6
Small C++ Test.
« Reply #18 on: 2006-04-27 02:41:27 »
Forgive my noobishness, but I don't quite understand #2. I understand it has something to do with short-circuit evaluation, but...

Code: [Select]

int I = 0, J = 0;

if ( I++ == 1 && I++ == 2)
J = 1;


Spoiler: show

Why doesn't that work?

Would it have to be:

if (I++ == 1 & I++ == 2)
J = 1;


L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Small C++ Test.
« Reply #19 on: 2006-04-27 03:24:44 »
To RPGillespie:
Spoiler: show
In the left side of the &&, I is compared as 0 (and increased afterwards) so the condition fails immediately and the right side is not evaluated at all.
This is what people mean by “short-circuit” method, and the C/C++ specification dictates that this is the correct behavior for two reasons.
1: Saves time; the right side does not need to be evaluated since the statement can’t be true anyway.
2: Allows you to check a pointer for NULL on the left side, then use indirection on the pointer on the right side.  If the pointer is NULL, the indirection on the left side will not cause an access violation because it isn’t evaluated at all.




To ficedula:
Spoiler: show
Ding ding ding ding!  Congratulations on being the first to note that some of these are undefined.   :D  There are two intentions here:
1: Bring about more awareness towards the types of things you should avoid while coding because the results may not be consistent across compilers.
2: Have a bit of fun by logically deducing what should happen if the ANSI C/C++ specification is not obscured by implementation.  The ANSI C++ specification says explicitly that values modified twice between sequence points yield undefined results, however the actual result can be logically deduced.  Luckily, however, because of the “undefined”/abstract nature of some of these problems, there are multiple correct deductions.



As for your reply to #4:
1: Sound spiteful much?  It’s not a who-understands-the-language-the-most game.
2: For all intents and purposes, there is no need to explain that the int pointers aren’t valid addresses; that much is clear at first glance.  But you are correct to deduce that the specifications don’t specifically define that the validity of constant pointers be verified at all during compilation (in fact doing so may lead to erroneous output across systems), so the result of constants 6 and 2 are just as valid as constants 0x100006 and 0x100002 (and both yield the same result).






And lastly, #7 is not undefined.
Take a second look at the rules for sequence points and order of evaluation.

The result seems undefined because of the two array indices (don’t let the other two I++ expressions mislead you; that’s the trick to this one), however the ANSI C++ specifications do dictate how to handle this situation (that does not mean every compiler will handle it correctly, as we have already seen some compilers as handling other defined expressions incorrectly).
Of course, this should be avoided at all costs, but tinkering with these problems is just for fun.


L. Spiro

ficedula

  • *
  • Posts: 2178
    • View Profile
    • http://www.ficedula.co.uk
Small C++ Test.
« Reply #20 on: 2006-04-27 06:53:00 »
Quote from: L. Spiro


To ficedula:
Spoiler: show
Ding ding ding ding!  Congratulations on being the first to note that some of these are undefined.   :D  There are two intentions here:
1: Bring about more awareness towards the types of things you should avoid while coding because the results may not be consistent across compilers.
2: Have a bit of fun by logically deducing what should happen if the ANSI C/C++ specification is not obscured by implementation.  The ANSI C++ specification says explicitly that values modified twice between sequence points yield undefined results, however the actual result can be logically deduced.  



Spoiler: show

Well, if by "logically deduced" you mean, "make a reasonable guess about what a particular version of a particular compiler might do", then yeah, you can do that. But undefined means just that: the compiler can legally do anything and remain spec-compliant. Can even change between compiler versions, which is why it's never any better than a guessing game.



Quote from: L. Spiro

Spoiler: show

2: For all intents and purposes, there is no need to explain that the int pointers aren’t valid addresses; that much is clear at first glance.  But you are correct to deduce that the specifications don’t specifically define that the validity of constant pointers be verified at all during compilation (in fact doing so may lead to erroneous output across systems), so the result of constants 6 and 2 are just as valid as constants 0x100006 and 0x100002 (and both yield the same result).


Spoiler: show

Bzzzzt, wrong? I don't believe the C++ spec mandates that pointers have to be simple integers containing the raw memory address they're pointing to. The three issues here are:

1) On systems where memory operations have to be aligned, 0x6 (and 0x100006) could never, ever point to an int [of 32-bits or more], and therefore while I suspect the spec doesn't cover this, trying to calculate the difference in indices between two locations when neither location can hold the value in question is ... dodgy.

2) I also believe - although I'm not sure - that the spec says that pointer comparisons between arbitrary values are undefined! ie. you can compare  pointers into a block returned from a single call to malloc/new, or you can compare pointers into an array, but comparing any two pointers is not guaranteed to do anything meaningful.
This would also mean the comparison could return literally anything.

3) On some systems, pointers actually contain more information than a memory address: for example, the low order bits contain information such as the type, size and format of data being pointed to, while the high order bits contain the actual addressing information. The comparison rule above is a direct consequence of C++ wanting to allow arbitrary schemes like this (since this is how pointers work in hardware on some CPUs!).

Again, that means you have no idea what meaning 0x2 or 0x6 have as a pointer. It's possible 0x6 is actually setting the hardware pointer flags PTR_READ_FROM_RANDOM_MEMORY_LOCATION and PTR_INVALID. Therefore you can't be sure what the comparison will return.


L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Small C++ Test.
« Reply #21 on: 2006-04-27 08:03:37 »
Quote
Spoiler: show
Well, if by "logically deduced" you mean, "make a reasonable guess about what a particular version of a particular compiler might do", then yeah, you can do that. But undefined means just that: the compiler can legally do anything and remain spec-compliant. Can even change between compiler versions, which is why it's never any better than a guessing game.

Spoiler: show
Actually I do mean that, or at least roughly similarly.
The specification specifies when and where postfix/prefix incrementations are supposed to be applied, also stating strictly that after which point the side-effects of these applications are to be final and for further processing discarded.
The reason it states that modifying variables twice between sequence points results in undefined behavior is because both implementations and code combinations are too broad to specify exact results for every situation.
Ultimately, it lays the ground rules, but then covers its tracks by specifying that certain cases are undefined, allowing leniency towards implementation methods.
This is why I stated that, with implementation aside, following the actual guidelines set forth by the ANSI C++ specification to a T, logical deductions can be drawn for most of the problems I have given.


However, by all means, you are correct.  These are deductions and no compiler is guaranteed to handle them “logically”.
Even if you were sure of what to expect, you would still have to waste time testing to make sure the compiler itself does what you expect, and ultimately it’s best to just avoid most of these cases altogether.








Quote
Spoiler: show
3) On some systems, pointers actually contain more information than a memory address: for example, the low order bits contain information such as the type, size and format of data being pointed to, while the high order bits contain the actual addressing information. The comparison rule above is a direct consequence of C++ wanting to allow arbitrary schemes like this (since this is how pointers work in hardware on some CPUs!).

Spoiler: show
In the best-case scenario, this is platform-specific, not part of a standard set by the ANSI C specifications.  In fact this applies to #1 also.
No part of C++ dictates that memory addresses have to be aligned; this is system-dependant which means that system may purposely compile the code to keep things aligned, but is required to do so only because of its own limitations rather than limitations inherent in C++.

No system is required by C++ to use registers a certain way, stacks a certain way, or to save/use pointers a certain way; some types of hardware were created to work this way, but by their own choices.

Again, it’s just not worth mentioning for my intentions in this thread.

Subtracting two pointers is the purpose of that question; nothing more.
I could have provided an example where I used malloc() to create two pointers and then subtracted them this way, and you wouldn’t have had anything to say.
But instead you decided to accuse me of playing a “who knows the most about C++” game and pick apart the nuances of my examples to make a point of your own.
And exactly what is your point?
Maybe you should be very clear on your exact intentions when you go about telling me exactly what things a person should be pointing out if he were to be playing that game.
Because accusing me of playing a “proving” game followed by nit-picking irrelevant details to make sure people know he is on top is just what someone should do, if he were just a tad spiteful.





For the record, I have no beef with you and I eagerly awaited your first reply, because I knew if there was one person here who would know about the tricks behind these questions, it would be you.
This test is for fun, and in the early posts it seemed as if people were actually having fun looking at these weirdo situations, so let’s try to keep it fun, shall we?


L. Spiro

dziugo

  • *
  • Posts: 1470
    • View Profile
    • A new copy of FF7 thanks to Salk. Pack (zip/rar/etc) your saved game before sending it to me.
Small C++ Test.
« Reply #22 on: 2006-04-27 09:21:51 »
I think that it doesn't matter if you spoiler-tag your post or not. There were too many replies to accidentally read the tip/answer by entering the thread and reading the first visible line :P

dziugo

ficedula

  • *
  • Posts: 2178
    • View Profile
    • http://www.ficedula.co.uk
Small C++ Test.
« Reply #23 on: 2006-04-27 09:55:10 »
My point is that teaching someone that pointer arithmetic is possible in C++ is a good point to make, but not also teaching them that it's undefined except under some very specific purposes is dangerous; you wouldn't want people to go away with the idea that "hey, we can perform all sorts of arithmetic on pointers, cool!". Or at least, you also want them to know: except in these cases, doing it may or may not work and we can't be sure.

Giving somebody the tools to shoot their own foot off is often desirable, but it's nice to mention how the safety works at the same time ;)

Same sort of idea applies with the pre-post increment operators: in my mind, the most important point to make with these under virtually any circumstances is that once you use two or more on the same variable between sequence points, the results are undefined. Not "well, it actually only does it once", but literally undefined.

(I should probably mention that the reason I feel so strongly about this is I'm currently porting our code base at work from Win32 to .NET and I've been bitten a few times by code where the person who wrote it just checked "does it work on the compiler I'm using", rather than "is this meant to work at all".)

The main reason I'm mentioning funky pointers containing non-address information is that, hey, I find that information kind of cool - how many people thought pointers were always just integers, a raw 'count' of bytes? It's sort of enlightening to realise "well, my PC does that, but..."

It's yet another thing I see people assuming all over the place, "well, pointers are just integers, right? I can just convert it to an integer and back again and it's just an address in memory..." - ie. they know enough to make it work some of the time...

L. Spiro

  • *
  • Posts: 797
    • View Profile
    • http://www.memoryhacking.com/index.php
Small C++ Test.
« Reply #24 on: 2006-04-27 12:36:09 »
Our lines of thought aren’t too far apart; there has just been a slight misunderstanding.

The questions I posed have various intentions, from illustrating short-circuit conditionals to demonstrating undefined and unpredictable results.

Quote
(I should probably mention that the reason I feel so strongly about this is I'm currently porting our code base at work from Win32 to .NET and I've been bitten a few times by code where the person who wrote it just checked "does it work on the compiler I'm using", rather than "is this meant to work at all".)

Incidentally, do you think that programmer would have coded the same way after taking this test?
People are seeing now many examples of types of code to avoid.
From the beginning people were seeing how many different results each compiler would produce, which has not only been fun and interesting, but a learning experience.


Quote
in my mind, the most important point to make with these under virtually any circumstances is that once you use two or more on the same variable between sequence points, the results are undefined. Not "well, it actually only does it once", but literally undefined.

I would like to think most people who took this topic seriously now have a very firm impression of this that will last a lifetime.
Now we have seen just exactly how dangerous it can be to disregard this rule, and more awareness towards the types of situations that can break this rule.

Likewise, a lot of programmers aren’t even aware that there are expressions that yield undefined results.

Spread the knowldege, I say.


L. Spiro