• (cs) in reply to waffles
    Devi:
    Fred:
    while (*p+=(*p++==',')<<1);

    I'm still trying to not think about what's actually happening in the first loop...

    Okay, I thought about it:

    while (*(p++)+=(*p==',')<<1);

    Fixed :)

    Edit:

    while (*p+++=(*p==',')<<1);

    I didn't expect that to happen O_O

  • (cs) in reply to Shinobu
    Shinobu:
    Is that for statement necessary?
    void ReplaceCommas (char* p) {
    	while(*p++ = *p == ',' ? '.' : *p);
    }
    Wouldn't that work too? The ++ should get executed after the rest of the expression, so it could equally well be on the second *p, I guess.

    Wait, is that guaranteed? There's no sequence point, so I'm skeptical, but I don't know the std well enough to actually say.

  • James (unregistered) in reply to mkb

    ZWINDOW STARCHILD

    Congratulations, you've just named Frank Zappa's next kid.

  • (cs) in reply to Derrick Pallas
    Derrick Pallas:
    You come to a fork in the code; at this branch, there are two sentinels. The specification tells you that one only lies and one only tells the truth, though it is not obvious to you which is which. One code path leads to exit(0) and one leads to exit(-1): asking only one sentinel a single question, how do you determine which branch to take?

    You ask either sentinel what the other one would say, then you go through the opposite door.

    This works because the liar will lie about what the truth teller would say and the truth teller will tell you what the liar will say, thus, both will tell you the same door: the wrong one.

  • (cs) in reply to James
    James:
    ZWINDOW STARCHILD

    Congratulations, you've just named Frank Zappa's next kid.


  • mrputter (unregistered) in reply to KenW
    KenW:
    You're all wrong. This is obviously code designed to handle old, set in their ways buffers that are resistant to change. ;-)

    Two words: "sticky registers."

  • sf (unregistered) in reply to snoofle
    snoofle:
    Chris Walton:
    Scare away newbies with a one-liner equivalent
    void ReplaceCommas (char* p) {
    	for(; *p; p++) *p = *p == ',' ? '.' : *p;
    }

    CAPTCHA: muhahaha (how fitting!)

    Lord! It's been ages since I've coded in "C" - you just don't get to do stuff like this (at least not with this syntax) in Java. Ah, the memories :)

    Java:
    public void replaceCommas(char[] p) {
        for (int i=0; i < p.length; i++) p[i] = p[i] == '.' ? ',' : p[i];
    }
    It's not that much worst is it?
  • (cs) in reply to strictnein
    strictnein:
    Derrick Pallas:
    You come to a fork in the code; at this branch, there are two sentinels. The specification tells you that one only lies and one only tells the truth, though it is not obvious to you which is which. One code path leads to exit(0) and one leads to exit(-1): asking only one sentinel a single question, how do you determine which branch to take?

    You ask either sentinel what the other one would say, then you go through the opposite door.

    This works because the liar will lie about what the truth teller would say and the truth teller will tell you what the liar will say, thus, both will tell you the same door: the wrong one.

    But what happens if there are three sentinels, one of which will send SIGKILL to your process if you ask a tricky question?

  • Anonymous Coward (unregistered)

    Most of your C examples, even if they work, are undefined:

    http://c-faq.com/expr/evalorder1.html

    Using the post-increment operator and referencing the lvalue incremented elsewhere in the same expression causes undefined behaviour.

  • Fred (unregistered) in reply to Devi
    Devi:
    Alan Balkany:
    void ReplaceCommas (char* p) { while(*p++ = *p == ',' ? '.' : *p); }

    Doesn't work: The post-increment operator makes the *p on the right-hand side different than the *p on the left-hand side.

    It works for me:

    
    
            // I just had to try this one out first...
    	while(*p+=(*p++==',')<<1);
    
    	printf("%s\n",buffer);
    

    Outputs:

    Hello,"my name is,"what,"my name is Hello."my name is."what."my name is

    On VC++ 2003.

    It seems that in the second conversion the increment is applied to p after the assignment.

    I'm still trying to not think about what's actually happening in the first loop...

    Well, I told you that was including undefined behavior (ie: results are different depending on where you put the ++). A true non portable wtf. ON Visual, you need "while(*p++ +=(*p==',')<<1)", on gcc "while(*p+=(*p++==',')<<1)" [ahah, shorter by one char, which proves the superiority of gcc! :-)]

    Btw, I sometimes answered to people asking for their homework to be done in mailing lists newsgroup with workable but evil code (Here for instance ) Maybe I am responsible for some of the wtf you have to maintain...

  • Shinobu (unregistered) in reply to EvanED
    EvanED:
    Shinobu:
    Is that for statement necessary?
    void ReplaceCommas (char* p) {
    	while(*p++ = *p == ',' ? '.' : *p);
    }
    Wouldn't that work too? The ++ should get executed after the rest of the expression, so it could equally well be on the second *p, I guess.

    Wait, is that guaranteed? There's no sequence point, so I'm skeptical, but I don't know the std well enough to actually say.

    Actually no, it isn't. Forgot about that; I haven't hacked in C for a while and it has all kinds of razorsharp edges everywhere... By the way, it used to work with the compiler I used "back then"* :-) So, here's take 2:
    void ReplaceCommas (char* p) {
    while(*p = *p == ',' ? '.' : *p) p++;
    }
    Minor fix, but now it would (always) work, right? *I know this not because I used it, but because of looking too much at the generated assembler.

  • (cs) in reply to Shinobu
    if ( ( f = dynamic_cast<zControl *>(child) ) != 0 )

    I thought I knew a good bit about C, but I must confess I've never seen *> before.

    Is x*>b shorthand for (*x)->b ?? (like how x->b is basically shorthand for (*x).b ) Or is like calling x.operator>(b) ??

    I really have no idea what the compiler parses that line to...

  • waffles (unregistered) in reply to kipthegreat
    kipthegreat:
    if ( ( f = dynamic_cast<zControl *>(child) ) != 0 )

    I thought I knew a good bit about C, but I must confess I've never seen *> before.

    Is x*>b shorthand for (*x)->b ?? (like how x->b is basically shorthand for (*x).b ) Or is like calling x.operator>(b) ??

    I really have no idea what the compiler parses that line to...

    That's the C++ version of if ( ( f = (zControl *)(child) ) != 0 )

  • diaphanein (unregistered) in reply to kipthegreat
    kipthegreat:
    if ( ( f = dynamic_cast<zControl *>(child) ) != 0 )

    I thought I knew a good bit about C, but I must confess I've never seen *> before.

    Is x*>b shorthand for (*x)->b ?? (like how x->b is basically shorthand for (*x).b ) Or is like calling x.operator>(b) ??

    I really have no idea what the compiler parses that line to...

    Its C++ and dynamic_cast<T*>(U*) does a polymorphic cast to T* from U* if T is an appropriate type for the cast, or returns a null pointer if the cast is invalid.

    If you're familiar with C#, its behavior is very similar to the 'as' operator.

  • The (unemployed) Graduate (unregistered) in reply to Devi

    Why not abstract the problem into a useful, reusable tool? If such a tool doesn't already exist, of course. ( Sorry, my cstdlib knowledge is a bit rusty )

    // replaces the target char in a string buffer with a substitute char
    void ReplaceChar ( char *buffer, char target, char sub )
    {
        for ( int i=0; i < strlen( buffer ); i++ )
            buffer[i] = ( buffer[i] == target ? sub : buffer[i] );
    }
    
    ReplaceChar( *buffer, ',', '.' );
    ReplaceChar( *buffer, '"', '\'' );
    
  • Michael (unregistered)

    I would say that, at least during active development, the second snippet is not necessarily worse than failure -- I have left normally-dead source code in quite a few places where I would drop debugging hooks (and where I got tired of re-writing the almost identical debugging code that I deleted three days before). Maybe I'm giving the developer too much credit, but that is what the switch with an empty default case looked like to me.

  • (cs) in reply to Fred
    Fred:
    "while(*p++ +=(*p==',')<<1)", on gcc "while(*p+=(*p++==',')<<1)" [ahah, shorter by one char, which proves the superiority of gcc! :-)]

    Only because you pussied out and put in a space to divide up the 3 plus signs, it compiles fine without it ;)

    I was curious though about how other compilers would deal with though, I followed up on:

    Anonymous Coward:
    Most of your C examples, even if they work, are undefined:

    http://c-faq.com/expr/evalorder1.html

    Using the post-increment operator and referencing the lvalue incremented elsewhere in the same expression causes undefined behaviour.

    And according to this:

    http://c-faq.com/expr/evalorder4.html

    We should be able to expect far more spectacular results than simply mistaking where the increment goes. I don't anybody has such a compiler to hand?

  • Chris Walton (unregistered) in reply to waffles
    Fred:
    while (*p+=(*p++==',')<<1);

    Wow!

    You win! :D

    That is so beautiful I could cry.

    captcha: cognac (cuz it tastes good)

  • diaphanein (unregistered) in reply to Fred
    Fred:
    Btw, I sometimes answered to people asking for their homework to be done in mailing lists newsgroup with workable but evil code (Here for instance ) Maybe I am responsible for some of the wtf you have to maintain...

    +1 evil This was great. Took me a few to realize you're generating a c app, compiling it and getting the compiler to give you the errors in the data file. (Evil) Genious.

  • jon (unregistered)

    The switch just does one thing every time, right? Let's replace it with that thing!

    while ( ( child = trav() ) != NULL )
    {
      if ( ( f = dynamic_cast<zControl *>(child) ) != 0 )
      {
        int      DomId = f->zChildWin::ctrlId();
        break;
      }
    }
    
  • JJS (unregistered)

    WWhhhat iiis te mattrr wiyht thexee peepll?!!! Ar thy drynking an codkng?!!!

  • Fred (unregistered) in reply to Devi
    Devi:
    Fred:
    "while(*p++ +=(*p==',')<<1)", on gcc "while(*p+=(*p++==',')<<1)" [ahah, shorter by one char, which proves the superiority of gcc! :-)]

    Only because you pussied out and put in a space to divide up the 3 plus signs, it compiles fine without it ;)

    OMG, you're right. I used to known that the C preprocessor takes the longer match. Maybe my C is getting rusty...

  • Dysan (unregistered)

    It's called Duff's device,

     switch (count % 8)  /* count > 0 assumed */
    {
       case 0:        do {  *to = *from++;
       case 7:              *to = *from++;
       case 6:              *to = *from++;
       case 5:              *to = *from++;
       case 4:              *to = *from++;
       case 3:              *to = *from++;
       case 2:              *to = *from++;
       case 1:              *to = *from++;
                         } while ((count -= 8) > 0);
     }
    

    got to love it when you INTERLACE controle structures.

  • TK (unregistered)

    Am I the only one who didn't read the submitters name and looked up Pallas' Law on Wikipedia? I found Marcus Antonius Pallas who "was the source of a law that stated that a free woman who married a slave would remain free if the master approved."

  • (cs)

    Snippet from under the rug:

    function WidgetCollection() {
      /* TODO: I should probably just use a generic event dispatcher instead of creating individual handlers */
      /***BEGIN INIT***/
      this._Init = function(o) {
          var p = "__Widget_", c = -1, i = -1, n;
          while( (++c < 100) && (/**/((n = p + ++i) == -42) || eval("document." + n + " != null")/**/) ); /*esoteric*/
          if (c == 100) throw "You already have 100 Widget Collections. I'm stopping you here.";
          eval("document." + n + " = o"); /* attach object to a global node */
          o.ID = n; /* make sure we know where we're attached */
          o.Widget_OnClick = eval("function() { return document." 
            + n /* create an onclick specific to this instance */
            + ".SwitchToWidget(this.WidgetCollReference); }"); 
          if (typeof(o.Widget_OnClick) == "undefined") {
              if (i != 0) throw "Your browser doesn't support multiple instances of Widget.";
              o.Widget_OnClick = function() { return document.__Widget_0.SwitchToWidget(this.WidgetCollReference); };
          }
      }
      this._Init(this);
      this._Init = null; delete this._Init;
      /***END INIT***/
      this.Widgets = new Array();
      this.SwitchToWidget = function(w) {
        if (typeof(w) == "string") w = this.GetWidget(w);
        if (w == null) return false; /* hide null calls */
        if (this.ActiveWidget == w) return false; /* already active */
        if (this.ActiveWidget != null) this.ActiveWidget.MakeInactive();
        this.ActiveWidget = w;
        this.ActiveWidget.MakeActive();
        return true;
      };
      /* ... */
    }
    
    
  • AT (unregistered) in reply to strictnein
    strictnein:
    That's the amazing thing about C++, sometimes it will tell you the truth, but every once in a while it will lie to you, just for kicks. That's why advanced programming techniques like the one shown come in handy. C++ will never lie twice in a row! It's part of the spec.

    I used to work with a programmer that honestly believed something like this... he would always nest an if() inside a while() or for() loop - "to be safe - because sometimes it doesn't work otherwise", i.e.

    while(condition) {
        if(condition) {
            /* do something */
        }
    }
    
    for(i=0; condition; i++) {
        if(condition) {
            /* do something */
        }
    }
    

    I tried explaining the insanity of doing this, but he thought I was the crazy one...

  • Anand Muthu (unregistered)

    Whats the algorithm that you have USED here ..? Its seems to be very complex :P

  • Anand Muthu (unregistered) in reply to Devi
    Devi:
    Devi:
    Fred:
    while (*p+=(*p++==',')<<1);

    I'm still trying to not think about what's actually happening in the first loop...

    Okay, I thought about it:

    while (*(p++)+=(*p==',')<<1);

    Fixed :)

    Edit:

    while (*p+++=(*p==',')<<1);

    I didn't expect that to happen O_O

    hhmmm... Devi giving explanation too to that code :P

  • proxy (unregistered) in reply to Devi
    Devi:
    Alan Balkany:
    void ReplaceCommas (char* p) { while(*p++ = *p == ',' ? '.' : *p); }

    Doesn't work: The post-increment operator makes the *p on the right-hand side different than the *p on the left-hand side.

    It works for me:

    int main()
    {
    	char buffer[100]="Hello, my name is, what, my name is";
    	char *p=buffer;
    
            // I just had to try this one out first...
    	while(*p+=(*p++==',')<<1);
    
    	printf("%s\n",buffer);
    
    	p=buffer;
    
    	while(*p++=(*p==','?'.':*p));
    
    	printf("%s\n",buffer);
    
    	getch();
    	return 0;
    } 
    

    Outputs:

    Hello,"my name is,"what,"my name is Hello."my name is."what."my name is

    On VC++ 2003.

    It seems that in the second conversion the increment is applied to p after the assignment.

    I'm still trying to not think about what's actually happening in the first loop...

    Well, while I can see why this code works (the compiler chooses the evaluate the r-value before the l-value...but it doesn't have too. In fact your code is strictly undefined do to sequence point rules.

  • (cs) in reply to Chris Walton
    Chris Walton:
    Scare away newbies with a one-liner equivalent
    void ReplaceCommas (char* p) {
    	for(; *p; p++) *p = *p == ',' ? '.' : *p;
    }

    <nitpick>That should be ++p to make it run faster, because you're not doing anything with the value of p in that statement.</nitpick>

  • anonymous (unregistered)

    buffer could point to an array of ports, in that case the same address might contain different values each time it is read ...

  • Chris Walton (unregistered) in reply to witch
    witch:
    Chris Walton:
    Scare away newbies with a one-liner equivalent
    void ReplaceCommas (char* p) {
    	for(; *p; p++) *p = *p == ',' ? '.' : *p;
    }

    <nitpick>That should be ++p to make it run faster, because you're not doing anything with the value of p in that statement.</nitpick>

    why is ++p faster?

  • (cs) in reply to Anand Muthu
    Anand Muthu:
    Devi:
    Devi:
    Fred:
    while (*p+=(*p++==',')<<1);

    I'm still trying to not think about what's actually happening in the first loop...

    Okay, I thought about it:

    while (*(p++)+=(*p==',')<<1);

    Fixed :)

    Edit:

    while (*p+++=(*p==',')<<1);

    I didn't expect that to happen O_O

    hhmmm... Devi giving explanation too to that code :P

    Yeah, I took me a while to work it out. It works because you can change a ',' to a '.' by adding 2 to it. So, if we simplify it and rearrange it a bit it looks like this:

    for (p=buffer; *p!=NULL; p++)
    {
       *p+= (*p==',') << 1;
    }
    

    I'm not sure if this is in the standard, but *p==',' resolves to 1 if p is a comma and 0 otherwise. By shifting once left 1 becomes 2, while 0 stays 0. Therefore the code says add 2 to *p if *p==',', otherwise add 0 to it.

  • (cs) in reply to Chris Walton
    Chris Walton:
    witch:
    <nitpick>That should be ++p to make it run faster, because you're not doing anything with the value of p in that statement.</nitpick>

    why is ++p faster?

    For any sane class that has had the ++ operators overloaded, the meaning of 'p++' means 'increment p, but give me back the previous value', whereas '++p' means 'increment p, and give me back the new value'. Since the latter doesn't require the method to remember the previous value, it's going to be faster.

    For integers and pointers, there won't be a speed difference.

    Since under normal circumstances ++x will always be at least as fast as x++, experienced C++ programmers will prefer to use the ++x form unless there's a good reason not to. (There is sometimes, usually in a '*x++' style of expression.)

  • Fred (unregistered) in reply to Chris Walton
    Chris Walton:

    why is ++p faster?

    Well, that used to be the case with naive compilers, because to compute i++, some naive compilers would do:

    • Fetch the value of i
    • Store it somewhere
    • Increment it
    • Store the result
    • Do something with the previous value

    With the motorola 68k, tables turned, because the processor had built-in support for post increment. So it was easy for compilers to be efficient when generating code like p[i++] = 42;

    Then, with C++, the opposite came true again, for classes. For complex types, the implementation of pre-increment can just return a reference to the object itself, while, for post-increment, the implementor of "++' have probably return a copy of itself in the non-incremented state. Hence all stl iterators use ++i, instead of i++.

    In the given example, p++ and ++p will be of exact same perfmance with a a reasonable compiler.

    captcha: onomatopoeia (wtf?)

  • Fred (unregistered) in reply to Devi
    Devi:

    I'm not sure if this is in the standard, but *p==',' resolves to 1 if p is a comma and 0 otherwise. By shifting once left 1 becomes 2, while 0 stays 0. Therefore the code says add 2 to *p if *p==',', otherwise add 0 to it.

    Yes, boolean operators evaluate to 0 or 1, this is in the standard. Of course, that '.'-',' is equal to 2 is not.

    captcha: onomatopoeia (again? wtf?)

  • Yes I am also bored (unregistered)

    void ReplaceCommas (char *buf) { int i,j; len=strlen(buffer);

    for (i=0; i < len; i++)
    {
        int comma=0;
        int not_a_comma=0;
        int j;
    
        for (j=0; j<100000; j++)
        {
            if (buffer[i]==',') 
            {
                comma++;
            } else {
                not_a_comma++;
            }
        }
    
        if (comma > not_a_comma) 
        {
            buffer[i]='.';
        }
    
        if (buffer[i]==',' && buffer[i]=='"')
        {
            buffer[i]='\'';
        }
    }
    
    return;
    

    }

    Democracy.

  • (cs) in reply to James
    James:
    ZWINDOW STARCHILD

    Congratulations, you've just named Frank Zappa's next kid.

    Frank Zappa is dead since Dec 4th, 1993. So how he is going to have a kid unless he got something stored before his death .... ?

    I concur with the name as such, though.

  • Old Wolf (unregistered) in reply to Shinobu
    Shinobu:
    Is that for statement necessary?
    void ReplaceCommas (char* p) {
    	while(*p++ = *p == ',' ? '.' : *p);
    }
    Wouldn't that work too? The ++ should get executed after the rest of the expression, so it could equally well be on the second *p, I guess.

    No, it causes undefined behaviour because without an intervening sequence point, "p" is both written, and accessed for a purpose other than determining the value ot be written.

  • Old Wolf (unregistered) in reply to calcnerd256
    calcnerd256:
    better: while(*p) *(p++) = *p == ',' ? '.' : *p;
    If you like formatting your harddrive.
    captcha: quake
    Why did you write that? Do you think anybody cares?
  • Old Wolf (unregistered) in reply to Devi
    Devi:
    Alan Balkany:
    void ReplaceCommas (char* p) { while(*p++ = *p == ',' ? '.' : *p); } Doesn't work: The post-increment operator makes the *p on the right-hand side different than the *p on the left-hand side.
    It works for me:
    int main()
    (etc.)
    The code is illegal in C. Your compiler may allow it, but you cannot rely on the result to be repeatable. It could turn out differently on another compiler; another version of the same compiler; or even another run of the same compiled code. Furthermore it could have any effect, including formatting your hard drive and so on. (This is not implausible in this case; the effect of the code could easily end up writing past the end of the array, and it could happen to overwrite some code that causes a jump into OS routines for disk formatting, etc.)
  • Old Wolf (unregistered)

    A WTF that nobody has explicitly mentioned yet: the code wastes time by scanning the string twice. (Once to find the length, and then once to perform the transformation). It would be better to check for the end terminator during the same pass as the transformation.

    Also, some people suggested (jokingly) that the extra checks could be in case the variable changes between reads. However this is not possible, as the variable is not declared 'volatile'. Most (if not all) compilers would optimize away all the extra reads and unreachable code.

    Finally, the suggested code that relies on ASCII values of ',' and '.' is of course non-portable, as that relation does not hold in EBCDIC and other character sets.

  • Old Wolf (unregistered) in reply to Devi
    Devi:
    while (*(p++)+=(*p==',')<<1);

    while (*p+++=(*p==',')<<1);

    In case it wasn't clear from my previous post; these ones cause undefined behaviour too, for the same reason.
  • Pallas (unregistered) in reply to TK

    There is a lot more to Pallas than that.

Leave a comment on “The Case for Switch”

Log In or post as a guest

Replying to comment #:

« Return to Article