LINUX.ORG.RU

Покритикуйте функцию вывода шестнадцатеричного числа без использования %X,


0

0

Просто тестовый пример, время выполнения 3 минуты

#include <stdio.h>

template < typename T > void print_hex ( T in_Value )\ { unsigned int half_byte = sizeof ( in_Value ) * 2; for ( int count = 0 ; count < half_byte ; count ++ ) { char symbol = in_Value >> ((half_byte - count - 1) * 4) & 0x0f; if ( symbol >= 0x0a ) { symbol += 'A' - 0xa; } else { symbol += '0'; } printf ( "%c" , symbol ); } }

int main ( int argc , char ** argv ) { print_hex < int > ( 0xABCDF0BA ); }

Мнение: опасный стиль


#include <stdio.h>

template < typename T >
void print_hex ( T in_Value )\
{
    unsigned int half_byte = sizeof ( in_Value ) * 2;
    for ( int count = 0 ; count < half_byte ; count ++ )
    {
        char symbol = in_Value >> ((half_byte - count - 1) * 4) & 0x0f;
        if ( symbol >= 0x0a )
        {
            symbol += 'A' - 0xa;
        }
        else
        {
            symbol += '0';
        }
        printf ( "%c" , symbol );
    }
}

int main ( int argc , char ** argv )
{
    print_hex < int > ( 0xABCDF0BA );
}

mumg
() автор топика
Ответ на: комментарий от mumg

для начала определись ты пишеш на С или С++

если точнее твоя программа это уже не С но ещё не С++ и вообще не соответсвует никакому стандарту на язык программирования

cvv ★★★★★
()
Ответ на: комментарий от mumg

char* p_itoa(int val, int base )
{
	static char buf[32] = {0};
	
	int i = 30;
	
	if (val == 0 )
	{ 
	    buf[i] = '0';
	    
	    return &buf[i]; 
	}
	else 
	{	
	    for(; val && i ; --i, val /= base)
	
		buf[i] = "0123456789abcdef"[val % base];
	
	    return &buf[i+1];
	}
}

BottleHunter
()
Ответ на: комментарий от cvv

> если точнее твоя программа это уже не С но ещё не С++ и вообще не соответсвует никакому стандарту на язык программирования

почему ты так считаешь?

dilmah ★★★★★
()
Ответ на: комментарий от BottleHunter

А критика где ? Эта функция не повторно входимая.

mumg
() автор топика
Ответ на: комментарий от dilmah

Давайте остановимся на варианте:

#include <stdio.h>

void print_hex ( int in_Value )
{
    unsigned int half_byte = sizeof ( in_Value ) * 2;
    for ( int count = 0 ; count < half_byte ; count ++ )
    {
        char symbol = in_Value >> ((half_byte - count - 1) * 4) & 0x0f;
        if ( symbol >= 0x0a )
        {
            symbol += 'A' - 0xa;
        }
        else
        {
            symbol += '0';
        }
        printf ( "%c" , symbol );
    }
}

int main ( int argc , char ** argv )
{
    print_hex ( 0xABCDF0BA );
}

mumg
() автор топика
Ответ на: комментарий от mumg

> Язык не принципиален, так что коментарий не уместен.

: PRINT_HEX ( int -- )
    BASE @  ( сохранили текущую систему счисления на стеке)
    SWAP    ( перенесли выводимое целое на вершину стека)
            ( а основание системы счисления под вершину)
    HEX .
    BASE !  ( восстановили текущую систему счисления со стека)
;

DECIMAL
15 PRINT_HEX CR
225 PRINT_HEX CR

HEX
FFAED PRINT_HEX CR
DEAD PRINT_HEX CR

13 BASE !
ABC PRINT_HEX CR
ABCD PRINT_HEX CR

DECIMAL

:-)

Neksys ★★★
()
Ответ на: комментарий от mumg

ну так пиши или на С или на С++. И радуйся что тебе попался компилер который в состоянии переварить твою ахинею. большинство компилеров отказываются компилить такой код при этом грязно ругаясь

cvv ★★★★★
()
Ответ на: комментарий от cvv

cvv, Вы вводите людей в заблуждение =))

cat /usr/include/stdio.h

... skip ...

#if !defined __need_FILE && !defined __need___FILE # define _STDIO_H 1 # include <features.h>

__BEGIN_DECLS

cat /usr/include/sys/cdefs.h

... skip ...

# define __BEGIN_DECLS extern "C" {

и в чём проблема, если код собирается g++?

legk
()
Ответ на: комментарий от legk

>и в чём проблема, если код собирается g++?

во первых не "собирается g++" а "собирается g++-2.95.3 или что там у вас", не все g++ такое переварят особенно последние.

>cat /usr/include/stdio.h

>... skip ...

>#if !defined __need_FILE && !defined __need___FILE # define _STDIO_H 1 # include <features.h>

>__BEGIN_DECLS

>cat /usr/include/sys/cdefs.h

>... skip ...

># define __BEGIN_DECLS extern "C" {

я вижу вы обрадовались "__BEGIN_DECLS" && "extern "C"". напрасно. это не всегда спасает даже при использовании g++.

cvv ★★★★★
()
Ответ на: комментарий от cvv

cvv, у меня сдается впечатление что програмированием Вы занимаетесь недавно. я пробовал компилить это под gcc 2.95.3 + gcc 3.4 + vs.net. так что не засоряте эфир.

mumg
() автор топика
Ответ на: комментарий от mumg

кстати расширение файла cpp, может наведет на умную мысль :)

mumg
() автор топика
Ответ на: комментарий от mumg

ладно оставлю я вас в покое только прочтите всётаки спецификации С++ и желательно не десятилетней давности

cvv ★★★★★
()
Ответ на: комментарий от cvv

sun 507> uname -a
SunOS fserv2 5.6 Generic_105181-33 sun4u sparc SUNW,Ultra-Enterprise
sun 508> cat main.cpp
#include <stdio.h>

template < typename T >
void print_hex ( T in_Value )\
{
    unsigned int half_byte = sizeof ( in_Value ) * 2;
    for ( int count = 0 ; count < half_byte ; count ++ )
    {
        char symbol = in_Value >> ((half_byte - count - 1) * 4) & 0x0f;
        if ( symbol >= 0x0a )
        {
            symbol += 'A' - 0xa;
        }
        else
        {
            symbol += '0';
        }
        printf ( "%c" , symbol );
    }
}

int main ( int argc , char ** argv )
{
    print_hex < int > ( 0xABCDF0BA );
}
sun 509> gcc main.cpp -o test.x
sun 510> ./test.x
ABCDF0BA

mumg
() автор топика
Ответ на: комментарий от cvv

кстати не будете ли так любезны указать, где тут используется C++ акромя template < typename T > ??? и при чем тут спецификации

mumg
() автор топика
Ответ на: комментарий от cvv

> только прочтите всётаки спецификации С++ и желательно не десятилетней давности

Коли сам не следуешь подобным советам - так и не советуй другим читать.
Уже сколько вопросов твоих буквально разжёвывается в начальных главах
в каждой книжке по Kernel Development.

Все любят давать советы, но мало кто исполняет...

RomanU
()
Ответ на: комментарий от mumg

> кстати не будете ли так любезны указать, где тут используется C++ акромя template < typename T > ??? и при чем тут спецификации

нет, ну если придраться, то как минимум:

< #include <stdio.h>
> #include <cstdio>

<   unsigned int half_byte = sizeof ( in_Value ) * 2;
<   for ( int count = 0 ; count < half_byte ; count ++ )

ну хотя бы на

>   size_t half_byte = sizeof ( in_Value ) * 2;
>   for ( size_t count = 0 ; count < half_byte ; count ++ )

..иначе, как минимум маты a'la "comparison between signed and unsigned integer expressions". то надо?

ну и само собой, значение из main все-таки стоит вернуть:

<    print_hex < int > ( 0xABCDF0BA );
<}
>    print_hex < int > ( 0xABCDF0BA );
>    return 0;
>}

ну и всеми любимый printf() лично я бы поменял на stream [будучи это все-таки C++].

ps: но тот же g++ 3.3.3 собирает это на ура, хотя и с указанными предупреждениями.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от RomanU

подожди ldd дочитаю да пару-тройку модулей напишу а там и поговорим.

mumg в отличие от меня не вчера сел за C++. непонятно только где его такому научили.

cvv ★★★★★
()
Ответ на: комментарий от legk

>Когда extern "C" не спасает???

тогда когда нарываешся на несовместимость С и С++. не любой С-код может быть скомпилен при помощи g++.

cvv ★★★★★
()
Ответ на: комментарий от cvv

> тогда когда нарываешся на несовместимость С и С++. не любой С-код может быть скомпилен при помощи g++.

AFAIU вы не совсем понимаете, зачем собссно нужен это таинственный 'extern "C"'.. :-/

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

а по моемому вы не поняли что я имел ввиду под "несовместимость С и С++. "

cvv ★★★★★
()
Ответ на: комментарий от klalafuda

а extern "C" предназначен для того что к плюсовому приложению можно было прилинковать pure C либы, но для начала нужно ещё создать то к чему линковать

cvv ★★★★★
()
Ответ на: комментарий от cvv

> mumg в отличие от меня не вчера сел за C++. непонятно только где его такому научили.

Дествительно это было лет 12 назад. А сейчас я работаю 
техническим лидером/мэнеджером команды из 25 человек и
 работаем мы в очень крупной outsorcing фирме. 
За плечами не один десяток проэктов. А этому меня не учили,
учат первые 2 месяца, а потом учишься сам. Но это не в тему.

Я бы хотел образумить вас, cvv, не делать резких высказываний
не имея опыта за плечами. Кроме вас ни у кого не возникло претензий
 к стилю, прошу обратить внимание. Причем ответа в чем проблема я не увидел.
Так что считаю претензии беспочвенными.


<   unsigned int half_byte = sizeof ( in_Value ) * 2;
<   for ( int count = 0 ; count < half_byte ; count ++ )

> ну хотя бы на

>   size_t half_byte = sizeof ( in_Value ) * 2;
>   for ( size_t count = 0 ; count < half_byte ; count ++ )

> ..иначе, как минимум маты a'la "comparison between signed and unsigned integer expressions". то надо?

> ну и само собой, значение из main все-таки стоит вернуть:

<    print_hex < int > ( 0xABCDF0BA );
<}
>    print_hex < int > ( 0xABCDF0BA );
>    return 0;
>}

> ну и всеми любимый printf() лично я бы поменял на stream [будучи это все-таки C++].

> ps: но тот же g++ 3.3.3 собирает это на ура, хотя и с указанными предупреждениями.

> klalafuda

klalafuda, спасибо за коментарии:
>   size_t half_byte = sizeof ( in_Value ) * 2;
согласен, полностью.
>    return 0;
тоже абсолютно согласен, но я спрашивал только касательно функции, хотя замечание к месту,
даже стыдно как то :)

История этого примера: это просто вопрос для собеседования для одного из работников в смежную команду,
а не реальный код который будет использоваться.

mumg
() автор топика
Ответ на: комментарий от mumg

>> mumg в отличие от меня не вчера сел за C++. непонятно только где его такому научили.

>Дествительно это было лет 12 назад. А сейчас я работаю техническим лидером/мэнеджером команды из 25 человек и  работаем мы в очень крупной outsorcing фирме. 

мама родная. я уверен что ваша фирма не обанкротилась на сей день только потому что ваши подчинённые не пишут такой ХХХХХ

>За плечами не один десяток проэктов. А этому меня не учили, учат первые 2 месяца, а потом учишься сам. Но это не в тему.

>Я бы хотел образумить вас, cvv, не делать резких высказываний не имея опыта за плечами. 

во первых опыт вообще у меня есть, но конкретно с с++ встречаюсь изредка, обычно pure C.

>Кроме вас ни у кого не возникло претензий к стилю, прошу обратить внимание. Причем ответа в чем проблема я не увидел. Так что считаю претензии беспочвенными.

а вы представте что вы завернули свою ф-ю в либу и отдали на использование в соседний отдел.

там нормальный программист пишет тестовую программу для вашей либы

#include <iostream>
#include <header_for_your_lib>

void main(){
  cout<<"hellow word!!!";

  print_hex < int > ( 0xABCDF0BA );

  cout<<"Done."
}

угадай-те что он получит в результате работы программы. Угадали? 

нет? правильно. результат работы  этой программы в общем случае непредсказуем. 

наберите в гугле "c++ mix cout printf", пройдите по первой ссылке и прочитайте Tip посреди страницы.

а ещё это же самое написано в info gcc но не во всех версиях.

cvv ★★★★★
()
Ответ на: комментарий от cvv

и все таки вы не поняли, не нужен cout или printf - ЭТО НЕ ПРИНЦИПИАЛЬНО. Этот пример не на вывод, а на алгоритм. Если придираться к мелочам: Будьте любезны, напишите с использованием cout НАДЕЖНУЮ программу для вывода на экран 20x20 звездочек.

mumg
() автор топика
Ответ на: комментарий от mumg

еще один коментарий, кстати такие методы как:

printf ( "something" ); std::cout << "bla bla bla " << std::flush; printf ( "dfkjhsdkfhskjf" ); std::cout << "dddd" << std::flush;

всегда предсказуемы. надеюсь я ничего для вас нового не сказал ?

mumg
() автор топика
Ответ на: комментарий от mumg

>всегда предсказуемы. надеюсь я ничего для вас нового не сказал ?

сказали. а я то думал что надо так

printf ( "something" ); fflush(stdout); std::cout << "bla bla bla " << std::flush; printf ( "dfkjhsdkfhskjf" ); fflush(stdout); std::cout << "dddd" << std::flush;

cvv ★★★★★
()
Ответ на: комментарий от cvv

а ещё по кошерному ваша ф-я должна принимать или указатель/ссылку на stream или возвращать какой-либо string нетрогая при этом никакие потоки кроме ,возможно, cerr/stderr.

cvv ★★★★★
()
Ответ на: комментарий от cvv

ну если совсем по кошерному, тогда так

fprintf ( stdout , "something" );
fflush(stdout);\
std::cout << "bla bla bla " << std::flush;
fprintf ( stdout , "dfkjhsdkfhskjf" );
fflush(stdout);
std::cout << "dddd" << std::flush;

а то как то целостность теряется :)
но не к тому батенька придираетесь.
Я же сказал, что функция print_hex не претендует на синхронизацию вывода. тут важен АЛГОРИТМ и время выполнения задания ( не выполнения функции).

mumg
() автор топика
Ответ на: комментарий от mumg

>ну если совсем по кошерному, тогда так

>fprintf ( stdout , "something" );fflush(stdout); >std::cout << "bla bla bla " << std::flush; >fprintf ( stdout , "dfkjhsdkfhskjf" );fflush(stdout); >std::cout << "dddd" << std::flush;

ну это уже похоже на спор о блондинках и брюнетках. результат работы то неизменится.

>Я же сказал, что функция print_hex не претендует на синхронизацию вывода. тут важен АЛГОРИТМ и время выполнения задания ( не выполнения функции).

а по этому поводу возмите во внимание мой предыдщуй пост.

cvv ★★★★★
()
Ответ на: комментарий от mumg

> тут важен АЛГОРИТМ и время выполнения задания ( не выполнения функции)

А чем тогда важен алгоритм, если не временем выполнения функции? Ну, и потреблением памяти?

Основные недостатки алгоритма:
1. Вычисление величины сдвига на каждой итерации - лишние вычисления.
2. Вычисление выводимого символа через if - громоздко и медленно.

Вот мой 3-минутный вариант:

void
print_hex( int value )
{
    static const int half_count = sizeof( value ) * 2;
    static const int shift = ( half_count - 1 ) * 4;
    int i;

    for( i=0; i<half_count; ++i, value<<=4 )
        cout << "0123456789ABCDEF"[ (value >> shift) & 0x0F ];
}

Тоже, кстати, не идеал.

watashiwa_daredeska ★★★★
()
Ответ на: комментарий от watashiwa_daredeska

> Тоже, кстати, не идеал.

в чём сокральный смысл "static const" vs "#define" ? все-таки память и ресурсы оно кушает.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от watashiwa_daredeska

#include <stdio.h>
#include <time.h>

void print_hex ( int in_Value )
{
    unsigned int half_byte = sizeof ( in_Value ) * 2;
    for ( int count = 0 ; count < half_byte ; count ++ )
    {
        char symbol = in_Value >> ((half_byte - count - 1) * 4) & 0x0f;
        if ( symbol >= 0x0a )
        {
            symbol += 'A' - 0xa;
        }
        else
        {
            symbol += '0';
        }
        printf ( "%c" , symbol );
    }
}
#define CICLES 100000

int main ( int argc , char ** argv )
{
    clock_t start, stop;
    int count;
    start = clock();
    for ( count = 0 ; count < CICLES ; count ++ )
    {
        print_hex(count);
    }
    stop = clock();
    printf("Elapsed time = %lf seconds\n",
        ((double)(stop - start)) / CLOCKS_PER_SEC);

    return 0;
}

Мой вариант:

Elapsed time = 0.340000 seconds

Твой вариант:

Elapsed time = 0.340000 seconds

Может имеет смысл отрубить вывод на экран, я перенаправлял в файл.
Я думаю дает знать скорость файловой системы.

mumg
() автор топика
Ответ на: комментарий от mumg

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

2. Если уж перенаправлял в файл, то перенаправлять нужно было в /dev/null.

watashiwa_daredeska ★★★★
()
Ответ на: комментарий от klalafuda

> в чём сокральный смысл "static const" vs "#define" ?

В большей общности. Есть случаи, когда #define не прокатывает, так зачем плодить разные решения одного и того же? К тому же, того, что можно объявить и так, и так - как правило, не так уж много и на потреблении памяти это практически не сказывается.

А с производительностью... Да, есть небольшие потери, но очень уж незначительные в большинстве случаев. А иногда даже и выигрыш.

watashiwa_daredeska ★★★★
()
Ответ на: комментарий от watashiwa_daredeska

> А с производительностью... Да, есть небольшие потери, но очень уж незначительные в большинстве случаев. А иногда даже и выигрыш.

в случае со static const -> непрерывное обращение к памяти в каждом цикле -> потенциальное непопадание в кеш CPU -> могут быть суровые накладные расходы. а могут и не быть, как повезет. в случае с #define (тут он IMHO вполне уместен) всё, что может, живет в регистрах и лишних обращений к памяти нет.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

> в случае со static const -> непрерывное обращение к памяти в каждом цикле

На самом деле, если ты посмотришь ассемблерный сурс этого кода после g++ -O2, то увидишь, что константы инлайнятся не хуже #define'ов. Поэтому, опять:

> зачем плодить разные решения одного и того же?

watashiwa_daredeska ★★★★
()
Ответ на: комментарий от watashiwa_daredeska

> На самом деле, если ты посмотришь ассемблерный сурс этого кода после g++ -O2, то увидишь, что константы инлайнятся не хуже #define'ов.

это было первое, что я сделал на приведённом примере перед тем, как утверждать.
именно для -O2 на gcc 3.3.3.
диагноз: нет, они не инлайнятся.
ибо и не должны.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

Это после g++-3.3 (GCC) 3.3.6 (Debian 1:3.3.6-10):

_Z9print_hexi:
.LFB1572:
    push    %ebp
.LCFI0:
    mov %ebp, %esp
.LCFI1:
    push    %esi
.LCFI2:
    mov %esi, 7
    push    %ebx
.LCFI3:
    sub %esp, 16
.LCFI4:
    mov %ebx, DWORD PTR [%ebp+8]
    .p2align 4,,15
.L6:
    mov DWORD PTR [%esp], OFFSET FLAT:_ZSt4cout
    mov %eax, %ebx
    shr %eax, 28
    movsx   %eax, BYTE PTR .LC0[%eax]
    sal %ebx, 4
    mov DWORD PTR [%esp+4], %eax
    call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_c
    dec %esi
    jns .L6
    add %esp, 16
    pop %ebx
    pop %esi
    pop %ebp
    ret

Что-то не видно обращений к _ZZ9print_hexiE10half_count,
_ZZ9print_hexiE5shift. Ибо всё заинлайнено и заоптимизировано.

watashiwa_daredeska ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.