Преобразование числа в разные обозначения - PullRequest
5 голосов
/ 17 января 2012

Это программа для преобразования числа в различные представления, такие как восьмеричное, десятичное, шестнадцатеричное и т. Д.

    #include<stdio.h>

    char *convert(unsigned int num, int base)
    {
    static char buff[33];
    char *ptr;
    ptr=&buff[sizeof(buff)-1];
    *ptr='\0';
    do
    {
    *--ptr="0123456789abcdef"[num%base];
    num/=base;
    }while(num!=0);
    return(ptr);
    }

    int main(){

    puts(convert(65,8));
    puts(convert(65,10));
    puts(convert(65,16));
    return 0;
    }

Выходные данные дают 101, 65 и 41 (то есть число '65', представленное в восьмеричной, десятичной и шестнадцатеричной записи соответственно)

Я очень хорошо понимаю, что происходит, но я никогда не сталкивался с чем-то вроде

*--ptr="0123456789abcdef"[num%base]

Я понимаю, как это работает, но я не понимаю, как это действительная запись. Кто-то, пожалуйста, объясните часть 0123456789abcdef (массив буквенных символов) здесь.

Ответы [ 3 ]

9 голосов
/ 17 января 2012

Это ужасная работа; кто бы ни написал его, его следует вынести за заднюю часть сарая и избивать до тех пор, пока он не пообещает больше никогда не писать такой код за пределами записи для IOCCC (Международного конкурса кодов с запутанным кодом C).

Правая часть выражения

*--ptr = "0123456789abcdef"[num%base];

использует тот факт, что строковый литерал преобразуется в указатель. Если вы видели:

const char digit[] = "0123456789ABCDEF";
*--ptr = digit[num%base];

вы бы не волновались. Выражение со строковым литералом эквивалентно этому. (По крайней мере, они имели благодать не писать:

*--ptr = (num % base)["0123456789ABCDEF"];

Это также эквивалентно в силу соотношения:

a[i] <==> i[a] <==> *(a + i) <==> *(i + a)

где двуглавые стрелки указывают на эквивалентность.

Использование *--ptr извлекает цифры назад, от наименее до наиболее значимого. Это работает, потому что указатель инициализируется до конца статического буфера (и очень важно, чтобы он был статическим, поскольку возвращаемое значение функции - указатель на этот буфер).

Однако код не очень полезен, потому что вы не можете сохранить значение из вызова и распечатать его позже, если был другой вызов. Вы не могли написать:

printf("%s = %s = %sn", convert(65,8), convert(65,10), convert(65,16));

Или, точнее, вы можете, но вы увидите одно и то же значение трижды один из «101», «164» или «140» в первой позиции, а также «01» или «64» или «40» для двух других позиций, и в стандарте C не указано, какие значения вы увидите. Статический буфер также предотвращает поточно-ориентированный код.

В общем, это странный код для показа новичкам. Это работает, но это все, что можно сказать об этом. Он также не проверяет свою базу на достоверность, поэтому convert(65, 18) может привести к неопределенному поведению. (База 17 в худшем случае будет ссылаться на '\0', который не был предназначен, что приводит к путанице.)

4 голосов
/ 17 января 2012

Ничего себе, это кратко и трудно читать. Я понимаю ваше замешательство, но я думаю, что могу помочь.

*--ptr = говорит: «Уменьшить этот указатель и присвоить некоторому значению адрес после уменьшения».

"0123456789abcdef" является литералом char массива.

[num%base] подписывается на предыдущий массив char, а индекс num по модулю base.

Эта строка включает в себя несколько вещей, которые, если их разложить полностью, будут выглядеть так:

char arr[] = "0123456789abcdef";
int subscript = num % base;
ptr = ptr - 1;
*ptr = arr[subscript];
1 голос
/ 17 января 2012

Его хитрая короткая рука - думай об этом больше так

char array[]="0123456789abcdef";
*--ptr=array[num%base];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...