Арифметический фрагмент указателя C - PullRequest
4 голосов
/ 12 мая 2009

У меня есть программа, которую я пытаюсь декодировать. Он переведен на C с другого языка (, имя которого здесь не произносится ), и, как я хочу понять, как он работает, я медленно переписываю код и упрощаю его, чтобы использовать все приятные логические конструкции C должен предложить.

В моем коде постоянно появляется следующее слово с различными значениями X и Y:

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

ptr имеет тип char *, и я не могу на самом деле делать предположения о состоянии массива в любой точке, потому что он довольно глубоко встроен в циклы и зависит от ввода и вывода. Я могу успешно «упростить» это до:

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

Но это просто ужасно. Чуть лучше:

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

Я хочу знать, может ли кто-нибудь придумать лучшее упрощение приведенного выше кода, я был бы очень признателен. Это происходит не менее чем в пяти местах и ​​отрицательно сказывается на моей способности упростить и понять управление потоком, поэтому, если кто-нибудь сможет предоставить более краткую / читаемую версию, это будет здорово. Если кто-то и может предложить какую-то причудливую информацию об этом коде, это тоже было бы здорово, хотя я в основном понимаю, что он делает.

Также может помочь понимание кода для X и / или Y. Y имеет тенденцию быть между -2 и 2, и X обычно равен 1, для чего стоит.

Ответы [ 4 ]

8 голосов
/ 12 мая 2009

ptr[X] эквивалентно *(ptr + X), поэтому мы можем переписать его следующим образом:

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

Теперь здесь много избыточности, поэтому мы можем упростить это до:

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

Тогда мы можем полностью избавиться от ptr_plus_x:

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

На английском языке мы посещаем места памяти со смещениями X, X + Y, X + 2Y, X + 3Y, ..., уменьшая каждую ячейку памяти, пока не найдем ячейку памяти, равную 0. Но тест 0 всегда происходит после уменьшения, поэтому мы действительно ищем первую ячейку памяти в этой последовательности со значением 1. Как только мы находим это, мы уменьшаем ее до 0 и завершаем работу.

Если Y равен 1, то мы уменьшаем строку последовательных ячеек памяти, идущих вперед, вплоть до первого 1. Если Y равен -1, то же самое происходит, но поиск выполняется со смещения X. Если Y равен 0 возникает бесконечный цикл. Если Y - любое другое значение, шаблон поиска пропускает различные записи.

Это не очень интуитивно понятная функция, поэтому я понимаю, почему вы запутались.

3 голосов
/ 12 мая 2009

Я добавлю:

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

сначала оцените, затем уменьшите (для условия while, то есть)

Редактировать: ОК, я буду ненавидеть себя утром. Гото на этом уровне в порядке, верно?

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

(честно говоря, я не знаю, оставить это или нет.)

EDIT2: так, как насчет этого? (TCC не жаловался)

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

РЕДАКТИРОВАТЬ 2 1/2;

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

Если ничего не помогает ..

РЕДАКТИРОВАТЬ3: Последний на сегодня.

while (ptr[X]--?ptr[X]--,ptr+=Y:0){
      if (!ptr[X]) break;
 }//good luck with this, it has been very amusing.
2 голосов
/ 12 мая 2009

Сайт, на котором написано, что он не должен быть назван:

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     }

Так что, кажется, его довольно легко преобразовать в C.

РЕДАКТИРОВАНИЕ: Вот BF Hello World, преобразованный в C ++.

0 голосов
/ 12 мая 2009

Уже довольно просто, как есть. Вместо того, чтобы писать меньше утверждений, я бы лучше попытался понять намерения и добавить комментарий.

Пример значения фрагмента «a»: уменьшить все элементы столбца (X) матрицы из Y столбцов. Вам может понадобиться нарисовать вертикальную линию +, например, на языке, который не имеет прямого назначения.

Вы можете уточнить это значение, показав индексы напрямую:

// 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 ];
    }
}

Удачи:)

...