views:

409

answers:

4

I have a program that I'm trying to decode. It is translated to C from another language (whose name is not spoken here), and as I want to understand how it works, I am slowly rewriting the code and simplifying it to use all the nice logical constructs C has to offer.

The following little bit keeps popping up in my code, with varying values of X and Y:

ptr[X]--;
while(ptr[X])
  {
    ptr[X]--;
    ptr += Y;
  }

ptr is of type char *, and I can't really make assumptions about the state of the array at any point because it's pretty deeply embedded in loops and dependent on input and output. I can successfully "simplify" that to:

for(ptr[X]--; ptr[X]; ptr[X]--, ptr += Y);

But that's just awful. Ever so slightly better is:

for(ptr[X]--; ptr[X]; ptr += Y) ptr[X]--;

I want to know if anyone can come up with a better simplification of the above code, I would greatly appreciate it. This occurs in no less than five places, and is impairing my ability to simplify and understand the flow control, so if anyone can provide a more consise/readable version, that would be awesome. If anyone can just offer any sort of fancy insight into that code, that would be awesome too, although I basically understand what it does.

Insight into the code for a specific X and/or Y can also help. Y tends to be between -2 and 2, and X is usually 1, for what its worth.

+3  A: 

I'll throw in:

ptr[X]--
while (ptr[X]--) ptr+=Y;

first evaluate, then decrement (for while condition, that is)

Edit: OK, i'll hate myself in the morning. Goto's are ok at this level, right?

dec:  ptr[x]--
      while (ptr[X]){
           ptr+=Y;
           goto dec;
      }

(i honestly dont know whether to leave this or not.)

EDIT2: so, how about this one? (tcc didn't complain)

 while (ptr[X]--?ptr[X]--,ptr+=Y:0){}

EDIT 2 1/2;

  //longshot
  while (ptr[X]--?ptr[X]--,ptr+=Y, ptr[X]:0){}

If all else fails..

EDIT3: Last one for tonight.

while (ptr[X]--?ptr[X]--,ptr+=Y:0){
      if (!ptr[X]) break;
 }//good luck with this, it has been very amusing.
Tom
This was one of the first things I tried, but it gives me a bus error. For what it's worth, adding `ptr[X]++` at the end DOES work, so it's just an off-by-one error.
Chris Lutz
Again, no, the post condition is wrong since you subtract too much from the final ptr[X].
paxdiablo
Re: goto: Leave it. It doesn't quite work (needs an extra ptr[X]-- at the beginning), but is highly amusing.
Chris Lutz
The new one produces a bus error, as well as the "warning: left-hand operand of comma expression has no effect" from GCC. Which is odd, because I think it should have some effect.
Chris Lutz
I was hoping that ternary operator would end the debate.
Tom
when doing a,b the return value of the whole expression is the return value of b. I think its too late alredy.
Tom
Now the ternary one doesn't produce a bus error, but instead loops infinitely. I think there's too much --ing in the ternary solution.
Chris Lutz
Maybe the array is to large? I've run some dummy tests with gcc (no "languange not discussed here") and it ends.
Tom
You are right, the -- before the ? is ruining it when the loop loops.
Tom
+8  A: 

ptr[X] is equivalent to *(ptr + X), so we can rewrite it as follows:

for((*(ptr + X))--; *(ptr + X); (*(ptr + X))--, ptr += Y);

Now there's a lot of redundancy here, so we can simplify this to:

char *ptr_plus_x = ptr + X;
for((*ptr_plus_x)--; *ptr_plus_x; (*ptr_plus_x)--, ptr_plus_x += Y);

Then we can get rid of ptr_plus_x entirely:

ptr += X;
for((*ptr)--; *ptr; (*ptr)--, ptr += Y);

In English, we visit the memory locations at offsets X, X+Y, X+2Y, X+3Y, ..., decrementing each memory location, until we find a memory location that is 0. But, the test for 0 always occurs after the decrement, so we're really looking for the first memory location in that sequence with a value of 1. Once we find that, we decrement it to 0 and quit.

If Y is 1, then we decrement a string of consecutive memory locations going forwards, up to and including the first 1. If Y is -1, the same thing happens, but searching backwards from offset X. If Y is 0, an infinite loop occurs. If Y is any other value, the search pattern skips various entries.

It's not a very intuitive function, so I can see why you're confused.

Adam Rosenfield
Either it's more confusing than either of us think, or it's just hard to look at out of context. This version gives me a bus error. I thought I would correct it by adding ptr -= X at the end of the for() loop, and this removes the bus error, but doesn't work (produces no output).
Chris Lutz
I would suggest to use pre decrement instead of post decrement and also to add the instruction ptr -= X after the loop instruction to restore exactly the ptr variable to exactly the same state as in the original code. Unless it is not needed of course.
chmike
Not an infinite loop if Y=0. Just makes the current location 0 (or underflows), without moving back or forth.
aib
A: 

It's quite simple as is, already. Instead of trying to write less statements, I would rather try to grasp the intent and add some comment.

An example of 'a' meaning of the snippet: decrease all elements of a column (X) of a matrix of Y columns. You would need that to draw a vertical line of +'ses, for instance, in a language that has no direct assignment.

You could clarify this meaning by showing the indices directly:

// set elements of column to cGoal
for( int decrementsToGoal = cGoal; decrementsToGoal != 0; --decrementsToGoal ) {
    // decrease all elements of column X
    for( int row = cMaxRows; M[ row*matrixsizeY + columnX ]; --row ) {
        --M[ row*matrixsizeY + columnX ];
    }
}

Good luck :)

xtofl
I don't necessarily want to reduce the number of statements, I just want to simplify the logic. In particular, I'm having problems with the fact that the loop affects both the pointer an the pointee, which is keeping me from simplifying it like I have done with other parts of the code.
Chris Lutz
I think xtofl might have got that idea from my statements. I was having fun :)
Tom
@Tom: Your code is almost as unreadable as a ... perl script :P
xtofl
+2  A: 

The website for it-which-shall-not-be-named states:

The semantics of the it-which-shall-not-be-named states commands can also
be succinctly expressed in terms of C, as follows (assuming that p has 
been previously defined as a char*):

>   becomes  ++p;
<   becomes  --p;
+   becomes  ++*p;
-   becomes  --*p;
.   becomes  putchar(*p);
,   becomes  *p = getchar();
[   becomes  while (*p) {
]   becomes  }

So it seems like it should be fairly easy to convert it over to C.

EDIT: Here is the Hello World BF converted to C++.

kitchen
I'm past that step. I used an optimized version of that same basic chart, so ++++ got translated to *p += 4;. Now I'm trying to reduce the code logic down to something more usable.
Chris Lutz
Can you post the piece of BF that is getting translated into that loop?
kitchen
It would be something like ">X-[->Y]<X", but change X and Y to X or Y number of >s or <s. "-[-<]" (straight from the source), where X is 0. (X has changed from the original translation because I've been messing with the code, but I verify that the simplified code does what it's supposed to, so it should all be functionally equivalent.)
Chris Lutz