C pointer arithmetic snippet

2019-06-26 05:29发布

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.

4条回答
不美不萌又怎样
2楼-- · 2019-06-26 06:06

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.
查看更多
在下西门庆
3楼-- · 2019-06-26 06:17

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.

查看更多
欢心
4楼-- · 2019-06-26 06:22

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 :)

查看更多
冷血范
5楼-- · 2019-06-26 06:23

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++.

查看更多
登录 后发表回答