Pixel swapping trick [SOLVED]

Started by
8 comments, last by MaulingMonkey 15 years, 9 months ago
In the most recent NeHe lesson, TGA loading, they handle BGR -> RGB using this trick: color[0] ^= color[2] ^= color[0] ^= color[2]; What advantages does this approach have, when compared to a more general: temp = color[0]; color[0] = color[2]; color[2] = temp; Thanks for your input. [Edited by - n00body on July 16, 2008 8:56:07 PM]

[Hardware:] Falcon Northwest Tiki, Windows 7, Nvidia Geforce GTX 970

[Websites:] Development Blog | LinkedIn
[Unity3D :] Alloy Physical Shader Framework

Advertisement
It has the advantage of being less readable and pretentiously clever... oh wait.

In other words, don't do what NeHe does here. It has no advantages.
Quote:Original post by n00body
In the most recent NeHe lesson, TGA loading, they handle BGR -> RGB using this trick:
color[0] ^= color[2] ^= color[0] ^= color[2];

What advantages does this approach have, when compared to a more general:
temp = color[0];
color[0] = color[2];
color[2] = temp;


Thanks for your input.


Other than not having to allocate space for the temp variable (a minuscule amount), none.
If you're given a programming test and you're asked how to swap two variables without a third temporary variable, you'll know how. :)
Patrick
Quote:Original post by n00body
color[0] ^= color[2] ^= color[0] ^= color[2];

This is actually undefined behavior because you're modifying those variables multiple times between sequence points.

The correct code for the XOR swap is the following:
color[0] ^= color[2];color[2] ^= color[0];color[0] ^= color[2];
Ra
Quote:Original post by Ra
Quote:Original post by n00body
color[0] ^= color[2] ^= color[0] ^= color[2];

This is actually undefined behavior because you're modifying those variables multiple times between sequence points.


Mind elaborating for the less understanding [embarrass]? The way I see it, you get right-associativity and the behaviour is well-defined as a ^= (b ^= (a ^= b)).
IRC logs just now, I'll edit this post to try and trim out the noise in a moment:

Quote:[18:20] <ra> color[0] ^= color[2] ^= color[0] ^= color[2]; <-- isn't this UB?
[18:21] <ra> the variables are being modified multiple times between sequence points
[18:21] <ra> because ^= is not a sequence point, right?
[18:21] <MaulingMonkey> ra, fuck yes it isn't
[18:21] <MaulingMonkey> So, yeah, UB.
[18:21] <_kw> ...
[18:22] <MaulingMonkey> Nope, you're wrong, _kw
[18:22] <_kw> how is that wrong?
[18:22] <MaulingMonkey> Operator precidence only affects how the expression is parsed
[18:22] <MaulingMonkey> That is, color[0] ^= (color[2] ^= color[0]);
[18:22] <jpetrie> Indeed.
[18:22] <jpetrie> Modification of the same value multiple times between sequence points. Undefined.
[18:23] * PlacidBox looks up a list of sequence points again
[18:23] <MaulingMonkey> ^= does not count as a sequence point, however, and thus this statement violates the rule in C++ that an integral type such as int cannot be read in the same expression that it is modified without an intervening sequence point.
[18:23] <MaulingMonkey> If you consider the expression:
[18:23] <MaulingMonkey> a() = b() = c()
[18:23] <MaulingMonkey> The C++ standard states that a, b, OR c can execute first.
[18:23] <MaulingMonkey> Because there are no sequence points.
[18:23] <MaulingMonkey> Thus, it's entirely valid for a() to be called first, then c(), then b()
[18:24] <MaulingMonkey> And similar fucked up situations.


Quote:[18:24] <_kw> but for example, a = b = 7;
[18:24] <_kw> there b=7 is executed first
[18:24] <_kw> and returns 7
[18:24] <_kw> or evaluates to 7 even
[18:25] <ra> _kw, for a = b = 7; it's a = (b = 7);
[18:25] <MaulingMonkey> But, the important part is that it results in 7
[18:25] <MaulingMonkey> b = a = b = 7 is undefined behavior
[18:25] <MaulingMonkey> Now, in that statement, b may or may not be assigned to 7 immediately.
[18:26] <MaulingMonkey> As in, before a is assigned to it.
[18:26] <notWtf> wtf, b = a = b = 7 is undefined behavior ???
[18:26] <_kw> a=b=7; is defined, but b=a=b=7 is undefined? :-/
[18:26] <jpetrie> Yes.
[18:26] <MaulingMonkey> notWtf: Two modifications of a single pod [simple types such as plain structs, ints, pointers, etc --MM] between sequence points, yes, very illegal
[18:26] <_kw> wtf..
...
[18:26] <notWtf> MaulingMonkey: well if things work in the correct order, like left to right, whats wrong
[18:27] <MaulingMonkey> notWtf: They don't always.
[18:27] <notWtf> orly
[18:27] <MaulingMonkey> notWtf: In fact, it usually varies by compiler.
[18:27] <MaulingMonkey> Consider:
[18:27] <MaulingMonkey> std::cout << ++i << ++i << ++i;
[18:27] <MaulingMonkey> This tends to spit out different values depending on your compiler.
[18:27] <MaulingMonkey> If i was 0, for example,
[18:27] <MaulingMonkey> It may print 1 2 3
[18:27] <MaulingMonkey> 3 3 3
[18:27] <MaulingMonkey> 3 2 1
[18:27] <MaulingMonkey> or 1 1 1


Full unedited logs in non-forum-breaky format
color[0] ^= color[2] as a subexpression appears twice in that statement. That means color[0] is assigned to twice in that statement.

There are no sequence points in that statement but for the trailing semicolon.

Thus, color[0] is assigned (written) twice before any sequence point.

The C++ standard says that the modification of a value more than once between sequence points is undefined behavior.

Thus, the expression is undefined behavior.
Quote:Original post by agi_shi
Quote:Original post by Ra
Quote:Original post by n00body
color[0] ^= color[2] ^= color[0] ^= color[2];

This is actually undefined behavior because you're modifying those variables multiple times between sequence points.


Mind elaborating for the less understanding [embarrass]? The way I see it, you get right-associativity and the behaviour is well-defined as a ^= (b ^= (a ^= b)).

Even with right-associative evaluation (which isn't necessarily the case per the standard) you're invoking undefined behavior because the values of a and b are modified more than once between sequence points (usually ;--there are other possible sequence points but none are present in this example unless a and b are user-defined types with overloaded ^= operators).
Ra
Okay, thanks for the info guys. I'll just stick to the more generalized approach.

[Hardware:] Falcon Northwest Tiki, Windows 7, Nvidia Geforce GTX 970

[Websites:] Development Blog | LinkedIn
[Unity3D :] Alloy Physical Shader Framework

A note I missed elaborating on:

I give some examples of what undefined behavior could do. Please be aware that in general, undefined behavior can be much worse. You know one of the most common security holes -- buffer overflows -- those things that silently crash your program hours later, or worse, let an attacker inject random code into your servers to be executed?

This happens because in C++, accessing beyond the end of an array constitutes -- you guessed it -- undefined behavior.

Executing a program compiled by a conforming C++ compiler (of which there are none that perfectly do) that invokes undefined behavior may legally launch nuclear missiles at a cow ranch in Alaska. I'm under the impression that, as half-joke, a version of GCC at one point would cause the program to launch the game nethack when invoking certain forms of undefined behavior.

This topic is closed to new replies.

Advertisement