Remkomplekty.ru

IT Новости из мира ПК
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Itoa си реализация

itoa () C реализация int min underflow

Я запускаю некоторые тестовые случаи против моей функции itoa (), но продолжаю получать

Я делаю проверку, но это то, что я пропустил здесь, что это?

7 ответов

не делать то, что вы думаете. C не имеет отрицательных целочисленных констант. Это беззнаковая константа int со значением 2^31, к которой применяется унарный оператор минус. Это означает, что выражение x == -21. будет зависеть от стандарта C компилятор использует.

если вы используете C99 или C11, вы будете в порядке. Существует подписанный тип, который достаточно большой-long long гарантированно будет достаточно большим для этого числа, поэтому как x, так и -21. будет преобразован в long long, а затем сравнивается. Но если вы используете компилятор C89, и у вашей машины недостаточно длинный тип, вы нажимаете поведение, определяемое реализацией:

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

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

Это выражение на самом деле имеет правильный тип и значение.

кроме того, я не вижу никаких ошибок в коде вас в курсе. Если это не проблема ft_intlen или ft_strdup ошибаетесь. Или вы вызываете свою функцию при тестировании неправильно (те же проблемы применяются к -21. когда вызов тестов).

статус: RESOLVED недопустимый

в любом случае, я улучшил некоторые моменты.

  • sizeof(char) всегда 1, нет необходимости в этом.
  • не бросайте malloc
  • если вы обрабатываете специальный случай 0, то просто обработайте его за один раз.
  • -2147483648 очень очень плохо. Вот что!—6—> для.
  • return не является функцией, не возвращайте (value) , просто вернуться value .
  • не s[len — 1] все время, лучше декременты len перед входом в цикл. Или, так как вам нужно len + 1 только в malloc звонок, просто len as intlen возвращает его и называют malloc используя len + 1

ft_itoa.c

main.c

результат

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

обратите внимание, что это использует новый size_t ft_uintlen(unsigned) функция, которая работает на unsigned аргументов.

вероятно, проблема в вашем механизме предотвращения переполнения. Вы пытаетесь назначить x типа int to n С типом long int . Но спецификация не гарантирует этот тип long int смогите отрегулировать ряд значения большой после этого int . Более подробную информацию можно найти » Long Vs. Int».

использовать long long int тип n если ваш компилятор поддерживает его. Обновите свой

потенциальные сбои кода, в порядке подозрения:

  1. ft_strdup() поскольку этот код вызывается с «int min value» и возникает ошибка.
  2. прототипы, отсутствующие для различных функций. Особенно ft_strdup()/strdup() .
  3. вызов / тестовый код неисправен.
  4. «int min value» больше, чем -2147483648. (Лучше использовать INT_MIN .)
  5. ft_intlen(n) неправильно закодирован и возвращает INT_MAX , то код пытается malloc(INT_MIN) .
  6. int/long 64-разрядная. Это беспорядок первый s[len — 1] = (n % 10) + ‘0’; С INT_MIN .

в противном случае, если INT_MIN имеет значение -2147483648, ft_itoa(int x) — это хорошо.

OP утверждает «. strdup просто выделяет строку, ft_intlen просто возвращает длину строки, оба проходят тестовые случаи-franklinexpress Oct 8 в 7: 52»

прохождение тестовых случаев не означает, что он работал без вызова неопределенного поведения. Лучше всего разместить ft_intlen() , ft_strdup() и теста для обзора.

кандидат портативный реализация. Не зависит int/long размер или дополнение 2. Нет необходимости
помимо CHAR_BIT какой код мог бы предположим, что это 8, не жертвуя слишком много питьевой. Работает с C89/99/11.

кусок кода, который вы дали, компилируется и работает на OsX, но с моим собственным ft_stdup и ft_intlen . Таким образом, вы можете либо показать нам код, либо проверить их на наличие ошибок. Я сделал несколько тестов (в том числе 2147483647, -2147483648). Это прекрасно работает.

во всяком случае, строки:

if (x == -2147483648) return (ft_strdup(«-2147483648»));

бесполезны, пока вы копируете свой x стоимостью в long long переменной (искусство) перед делать любой вид деятельности оно. Так что вам не нужно включать types.h (пресловутый moulinette не даст вам -42).

бывает, что на OsX он работает и на long значения, но это не портативный безопасный.

причина этого в том, что некоторые компиляторы могут иметь проблемы с пониманием этого числа.

стандартная библиотека C ограничения.h обычно определяют его как:

itoa (Си)

Ты — не раб!
Закрытый образовательный курс для детей элиты: «Истинное обустройство мира».
http://noslave.org

Функция itoa — широко распространённое нестандартное расширение стандартного языка программирования Си. Её использование не предусматривает переносимости, поскольку эта функция не определена ни в одном стандарте языка Си; тем не менее, зачастую компиляторы поддерживают её за счет использования заголовка , причем не совсем в удобном виде, так как она весьма близка по смыслу к стандартной библиотечной функции atoi .

void* itoa(int input, char *buffer, int radix)

itoa принимает передаваемое целое число input и конвертирует его в число в основании корня radix . Полученное число (последовательность цифр основания radix ) записывается в буфер вывода buffer .

Аргумент radix определяет основание системы исчисления для input; его значение может лежать в пределах от 2 до 36.

В зависимости от реализации, itoa может возвращать указатель на первый символ в буфере buffer , или может быть создана таким образом, чтобы передавать нуль- buffer , в результате чего функция возвращает длину строки, которая была записана в корректный buffer .

Для преобразования числа в строку с основанием 8 (восьмеричная), 10 (десятичная) или 16 (шестнадцатеричная система счисления) альтернативой, совместимой со стандартом, является использование стандартной библиотечной функции sprintf .

Содержание

Реализация от Кернигана и Ритчи

Функция itoa появилась в первом издании книги Брайана Кернигана и Дениса Ритчи Язык программирования Си, на странице 60. Второе издание Язык программирования Си («K&R2») на стр. 64 содержало нижеследующую реализацию itoa . В книге отмечено несколько вопросов, связанных с этой реализацией, включая тот факт, что она не в состоянии корректно обработать самое маленькое отрицательное число −2 длина машинного слова в битах-1 . [1]

Функция reverse реализована двумя страницами ранее:

Функция itoa (а также схожая с ней функция ftoa , конвертирующая числа с плавающей запятой в строку) указана в первой версии руководства по Unix. [2] В отличие от приведённых выше версий, библиотечная Unix-версия имела интерфейс, примерно похожий на

void itoa(int input, void (*subr)(char))

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

См. также

Напишите отзыв о статье «Itoa (Си)»

Примечания

  1. Решение этого вопроса смотри [http://clc-wiki.net/wiki/K%26R2_solutions:Chapter_3:Exercise_4 «K&R2 solutions»] на сайте clc-wiki.net.
  2. [http://cm.bell-labs.com/cm/cs/who/dmr/1stEdman.html «Unix Programmer’s Manual»], 3 ноября 1971. Глава [http://cm.bell-labs.com/cm/cs/who/dmr/pdfs/man31.pdf «Library routines»].

Ссылки

  • [http://cpp.pastebin.com/f154baf81 string itoa(int n)] — Функция C++ конвертации int в string (без утечек памяти!) (англ.)
  • [http://www.jb.man.ac.uk/

slowe/cpp/itoa.html How do I use itoa() with GCC?] — реализации itoa() с тестами производительности (англ.)

  • [http://boost.org/libs/conversion/lexical_cast.htm lexical_cast] — альтернатива для C++, часть библиотек boost (англ.)
  • [http://code.google.com/p/stringencoders/wiki/NumToA modp_numtoa] — альтернатива для C/C++ для преобразования целых и чисел с плавающей точкой в символы. (англ.)
  • [http://sourceforge.net/projects/itoa/ Good old Integer To Ascii conversion: itoa] — Еще одна достаточно быстрая реализация itoa для различных типов данных, плюс некоторая обертка в стиле boost в виде специализаций шаблона boost::lexical_cast (англ.) .
  • [http://www.codenet.ru/progr/cpp/spr/263.php Описание itoa] (рус.)
  • Отрывок, характеризующий Itoa (Си)

    (О Ключе Богов и, правда, ходят разные-преразные легенды. На каких только языках веками не пытались расписывать самые большие изумруды. На арабском, иудейском, индусском и даже на латыни. Только никто почему-то не хочет понять, что от этого камни не станут волшебными, как бы сильно кому-то этого не хотелось. На предлагаемых фотографиях видны: иранский псевдо Мани, и Великий Могул, и католический «талисман» Бога, и Изумрудная «дощечка» Гермеса (Emeral tablet) и даже знаменитая индийская Пещера Аполлона из Тианы, которую, как утверждают сами индусы, однажды посетил Иисус Христос. (Подробнее об этом можно прочитать в пишущейся сейчас книге «Святая страна Даария». Часть1. О чём ведали Боги?))
    – Просто сработала, видимо, у кого-то когда-то родовая память, и человек вспомнил – было когда-то что-то несказанно великое, Богами подаренное. А вот ЧТО – не в силах понять. Так и ходят столетиями «искатели» неизвестно зачем и кружат кругами. Будто наказал кто-то: «пойди туда – не знаю куда, принеси то – не ведомо что». Знают только, что сила в нём скрыта дюжая, знание невиданное. Умные за знанием гоняются, ну а «тёмные» как всегда пытаются найти его, чтобы править остальными. Думаю, это самая загадочная и самая (каждому по-своему) желанная реликвия, существовавшая когда-либо на Земле. Теперь всё только от тебя будет зависеть, светлая моя. Если меня не станет, ни за что не теряй его! Обещай мне это, Мария.
    Магдалина опять кивнула. Она поняла – то была жертва, которую просил у неё Радомир. И она ему обещала. Обещала хранить удивительный Ключ Богов ценой своей собственной жизни. да и жизни детей, если понадобится.
    Радомир осторожно вложил зелёное чудо ей в ладонь – кристалл был живым и тёплым.
    Ночь пробегала слишком быстро. На востоке уже светало. Магдалина глубоко вздохнула. Она знала, скоро за ним придут, чтобы отдать Радомира в руки ревнивых и лживых судей. всей своей чёрствой душой ненавидевших этого, как они называли, «чужого посланника».
    Свернувшись в комок меж сильных рук Радомира, Магдалина молчала. Она хотела просто чувствовать его тепло. насколько это ещё было возможно. Казалось, жизнь капля за каплей покидала её, превращая разбитое сердце в холодный камень. Она не могла дышать без него. Этого, такого родного человека. Он был её половиной, частью её существа, без которого жизнь была невозможна. Она не знала, как она будет без него существовать. Не знала, как ей суметь быть столь сильной. Но Радомир верил в неё, доверял ей. Он оставлял ей ДОЛГ, который не позволял сдаваться. И она честно пыталась выжить.
    Несмотря на всю нечеловеческую собранность, дальнейшего Магдалина почти не помнила.

    Читать еще:  Динамические структуры данных паскаль

    Она стояла на коленях прямо под крестом и смотрела Радомиру в глаза до самого последнего мгновения. До того, как его чистая и сильная душа покинула своё ненужное уже, умершее тело.На скорбное лицо Магдалины упала горячая капля крови, и слившись со слезой, скатилась на землю. Потом упала вторая. Так она стояла, не двигаясь, застывшая в глубочайшем горе. оплакивая свою боль кровавыми слезами.
    Вдруг, дикий, страшнее звериного, крик сотряс окружающее пространство. Крик был пронзительным и протяжным. От него стыла душа, ледяными тисками сжимая сердце. Это кричала Магдалина.
    Земля ответила ей, содрогнувшись всем своим старым могучим телом.
    После наступила тьма.
    Люди в ужасе разбегались, не разбирая дороги, не понимая, куда несут их непослушные ноги. Будто слепые, они натыкались друг на друга, шарахаясь в разные стороны, и снова спотыкались и падали, не обращая внимания на окружаюшее. Всюду звенели крики. Плачь и растерянность объяли Лысую Гору и наблюдавших там казнь людей, будто только лишь теперь позволив прозреть – истинно увидеть ими содеянное.

    C itoa реализация

    В качестве упражнения я ограничил себя на страницах руководства. Я не искал предыдущую существующую реализацию, потому что я хотел посмотреть, как хорошо я могу заниматься самостоятельно. Я также пытался обрабатывать столько случаев, о которых я мог подумать. Я уверен, что есть недостатки, поэтому не стесняйтесь указывать их. Где я могу улучшить свое использование стандартной библиотеки C и т. Д.

    3 ответа

    Нет причин использовать математику с плавающей запятой. Как минимум, он создает непереносимость, поскольку аспекты математики FP имеют угловые случаи и проблемы с точностью, которые не сработают itoa(int i) . В худшем случае он вызывает неопределенное поведение: abs(tmp) может быть UB, если tmp == INT_MIN . (Код использует tmp = (i == INT_MIN) ? (i + 1) : i; для обработки этого случая, но он вызывает обработку чище другими способами.) Редкий, но потенциальный неточный результат от —- +: = 4 =: + —- приводит к отключению с помощью log10() . C не указывает, что floor() может представлять каждый double . Подумайте о 64-битном int и 64-bit int . Код типа double является потенциальной ошибкой преобразования.

    Код очищает глобальное значение в коде, что очень неожиданно для этого. // Many issues digit_cnt = floor(log10(abs(tmp))) + 1; Я бы не ожидал побочного эффекта feclearexcept(FE_ALL_EXCEPT); , чтобы очистить исключения FP.

    itoa() является еще одним неожиданным побочным эффектом этого errno = 0 . Например itoa() и другие функции преобразования, установка strtol() to errno является ответственностью вызывающего абонента. C не указывает, что 0 устанавливается на некоторое значение в памяти. Поскольку этот пост не помечен как специфичный для ОС, я нахожусь на заботе о том, следует ли установить errno для указания этой ошибки.

    Чрезмерная errno . Просто malloc() необходимое пространство, а не самый худший размер. Я вижу, что OP является правильным, но опасным способом , Код OP основан на malloc() , который соответствует точному ответу, когда log10() . Известно, что слабые математические библиотеки FP выходят за рамки ожидаемого значения. Только это может привести к неправильному преобразованию, это приведет к повреждению памяти.

    Избегайте имени i == power-of-10 , которое хорошо используется другими.

    Примечание: C99 или более поздняя зависимость. itoa() и tmp % 10 может не вернуть значение ожидаемый с ранними претендентами. Я это замечаю, но не думаю, что стоит потратить усилия на то, чтобы учесть этих сотрудников. YMMV

    В целом хорошая попытка, но начиная с FP, действительно сложнейшие вещи и создаются ненужные зависимости от математики /атрибутов FP. Математика FP использовалась только для определения размера буфера, когда вместо промежуточных результатов мог использоваться буфер наихудшего случая. Думая о встроенном проекте, включение tmp /= 10 — это особенно дорогостоящее пространство и время.

    Простая альтернатива C99.

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

    Вы забыли #include все нужные заголовки. По моему мнению, это

    Плюс везде, где print_error_msg ; это неопределенный символ в коде, который вы опубликовали. Я предполагаю, что он делает что-то похожее на perror(NULL) ?

    Если бы я писал itoa , я бы начал с предположения, что у меня уже было выделение памяти. Тогда заполнение буфера так же просто, как и то, что вы написали:

    (я бы использовал специальный код 0 и INT_MIN в верхней части функции, чтобы мы не беспокоились о них здесь.)

    Тогда единственным недостающим элементом является . Но это легко — нам просто нужно написать код для подсчета цифр number . И мы уже имеем код print цифры number ! Поэтому я просто повторю этот код еще раз.

    Там — единственные заголовки, которые нам нужны, были (для malloc ) и, возможно,
    (для INT_MIN )

    Обратите внимание, что я написал ‘0’ + x , где вы написали (char)((int)’0′ + x) . C не является Pascal или Python; нет необходимости перепрыгивать через обручи, например chr(ord(‘0’) + x) . Символами в C являются малые целые числа, и вы можете делать математику на них так же, как можете, на любом другом целочисленном типе.

    Кроме того, вы должны выполнять математику по типам символов, если она устраняет необходимость в операции литья. Тип-литье в C и C ++ — это запах кода; если вам действительно нужен бросок, что-то ужасно неправильно с вашим кодом. В этом случае, к счастью, он вам не нужен.

    Читать еще:  Длина окружности паскаль

    В другом месте, в котором используется ваш код,

    Престижность использования ‘’ вместо 0 ; это хороший способ указать читателю, что этот конкретный ноль семантически представляет. Но убить актеров! В этом случае вы считаете, что вам нужен актерский состав, потому что ret является void* . Однако, единственные места, которые вы ссылаетесь на ret , вы передали его в char* . Это огромный признак того, что ret действительно хочет быть char*

    Проблема решена. ret не был бизнес void* в на первом месте.

    Нет комментариев о теоретической корректности материала с плавающей запятой; потому что, как я уже сказал, я бы не использовал число с плавающей запятой для печати целых чисел. Тем не менее, я протестировал ваш код на всех 4-х битных 32-битных целых числах и могу сообщить, что он отлично работает на практике.

    В этой функции вы можете избежать использования malloc . Многие функции утилиты оставляют все управление памятью до вызывающего абонента — вызывающий должен предоставить буфер и его размер. В вашей реализации вызывающий должен знать, как освободить возвращаемый указатель после использования.

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

    Но они также могут использовать функцию для печати непосредственно в существующий буфер, не требуя дополнительной копии.

    Кроме того, типичная реализация itoa обычно принимает значение radix в качестве аргумента, поэтому вы также можете использовать его для печати в шестнадцатеричном или двоичном , Поддержка оснований так же просто, как замена 10 s с помощью radix .

    Implementation of itoa()

    How can this solution be improved?

    Как можно улучшить это решение?

    How about just use ‘snprintf()’? – Jeff Mercado 21 ноя. 11 2011-11-21 21:12:19

    @JeffMercado: The only thing that’s better with snprintf is that it’s standard. Apart from that, it is a horrible slow function that can’t be used in application with high real time demands. – Lundin 22 ноя. 11 2011-11-22 10:34:05

    Funny part. This code is almost exactly Kernighan & Ritchie solution. So it is K&R code review! (source https://en.wikibooks.org/wiki/C_Programming/C_Reference/stdlib.h/itoa) – MajesticRa 24 июл. 16 2016-07-24 19:48:45

    2 ответа

    I think I’d break this up into a few separate routines, each with a single more specific intent. I think the easiest way to do this is probably to start by taking the absolute value of the input (represented as an unsigned type), something like this:

    I believe C’s requirements for converting a signed to unsigned ensure that this produce correct results for all inputs (including INT_MIN).

    With that, nearly everything else can deal with an unsigned number. Personally, I also prefer to generate the result in order instead of generating in reverse, then reversing it. One fairly simple way to do that is with recursion, with each step first generating previous numerals (if any), then adding its own numeral to the end of the string. I’d have the recursive function deal only with an unsigned type (as produced above). Of course, like nearly everything that manipulates data in a buffer in C, you should also pass the maximum buffer length for it to use, to prevent buffer overruns. For the sake of generality, I’ve also made it accept the base for the conversion as a parameter instead of always assuming base 10.

    Then I’d have a small wrapper function that puts in a — if the input is negative, invokes the function above with the absolute value of the input, and terminates the string after the internal function returns.

    This should also make it pretty trivial to write a utoa that handles unsigned inputs — it would be like itoa without the code to deal with negative numbers. As a minor refinement, I’d probably also make iabs and itoa_internal static functions to minimize the chances of them interfering with other names.

    It is probably bad practice to use ‘unsigned’ to implicitly refer to ‘unsigned int’. If I remember correctly, this is one of the things the C committee will make obsolete in future language standards. The best is of course to use the C99 int types from stdint.h (uint8_t, uint16_t etc) if C99 is available. Also, I don’t see why you would use recursion for this, a plain for loop will both be faster and easier to read. – Lundin 22 ноя. 11 2011-11-22 10:57:50

    @Lundin: Why would it be bad practice? Do you think somebody might think it referred to a nonexistent unsigned float type? I can’t imagine the committee changing this — it would gain nothing, and break huge amounts of code. In this case, the types for ‘stdint.h’ would be detrimental. I used recursion because I’ve yet to see an iterative version that was nearly as clean. «Recursion => slow» has been obsolete for a decade or more. – Jerry Coffin 22 ноя. 11 2011-11-22 11:57:27

    I’m not sure from where I heard that it may become obsolete, but anyway, there’s no reason why you can’t type out 3 more letters just in case, it isn’t that big an effort and makes the code clearer. stdint.h could actually improve the code further — if you know the size of an int, then you can tell whether the [len] parameter is valid or not, if you know that int is 16 bits, then len shouldn’t be longer than 5 letters + 1 null. – Lundin 22 ноя. 11 2011-11-22 12:26:34

    I don’t see how recursion could be optimized by the compiler and still C standard-compliant? A function call is a sequence point and all side effects must be complete before the function is called. With all the side effects in place, I don’t see how the compiler could unroll the recursion on its own? Also, if it _is_ standard-compliant, mustn’t it be tail recursion if the compiler should have any chance at all of optimizing it? I suspect whether the compiler is allowed/able to do this is highly language-dependent. – Lundin 22 ноя. 11 2011-11-22 12:42:15

    IMO, it does not make the code any clearer. Do you also think there’s some improvement from replacing ‘int x;’ with ‘auto signed int x;’? If so, why? If not, why should one use defaults but not the other? Faster recursion is a result of hardware improvements (branch prediction, on-chip return stack, on-chip stack). – Jerry Coffin 22 ноя. 11 2011-11-22 15:43:38

    As far as the types go, I see two obvious problems: first, it would be silly to reject a call just because the type *could* hold a value too large for the buffer. Second, these allow the user to specify the base, so (to use your example) that 16-bit integer *could* require up to 17 characters. – Jerry Coffin 22 ноя. 11 2011-11-22 16:00:35

    Or you can use the mathematical definition of ‘abs()’; ‘sqrt(pow(val, 2))’. – motoku 15 мар. 15 2015-03-15 02:42:01

    @MotokoKusanagi: I suppose you could, but I doubt you’d want to—it’s likely to be slower and less accurate than most others. – Jerry Coffin 15 мар. 15 2015-03-15 04:23:25

    Just some general idea about the code (without any effort to create a better algorithm).

    First of all, I agree with @Jeff, if there is a library for that use it. You don’t have to maintain it and everybody will know what the code does.

    So, code. I would use longer variable names:

    Читать еще:  Кто разработал язык паскаль

    I prefer one declaration per line because it’s easier to read and find the type of variables.

    It looks cool but hard to maintain. Just some questions:

    • Why is it here?
    • Is it intentionally = (and not == )?
    • Why isn’t it in a line before?

    If you have to maintain this code these kind of question could be hurt. So, I would write

    The questions are the in the while loop:

    Finally, I guess there is a potential buffer overflow if the caller pass too small char array to the function.

    Создан 21 ноя. 11 2011-11-21 22:44:10 palacsint

    Good comments. There is nothing gained by merging several rows into one, that’s just obfuscation and makes the code less readable. – Lundin 22 ноя. 11 2011-11-22 10:39:15

    Implementation of itoa()

    How can this solution be improved?

    Как можно улучшить это решение?

    How about just use ‘snprintf()’? – Jeff Mercado 21 ноя. 11 2011-11-21 21:12:19

    @JeffMercado: The only thing that’s better with snprintf is that it’s standard. Apart from that, it is a horrible slow function that can’t be used in application with high real time demands. – Lundin 22 ноя. 11 2011-11-22 10:34:05

    Funny part. This code is almost exactly Kernighan & Ritchie solution. So it is K&R code review! (source https://en.wikibooks.org/wiki/C_Programming/C_Reference/stdlib.h/itoa) – MajesticRa 24 июл. 16 2016-07-24 19:48:45

    2 ответа

    I think I’d break this up into a few separate routines, each with a single more specific intent. I think the easiest way to do this is probably to start by taking the absolute value of the input (represented as an unsigned type), something like this:

    I believe C’s requirements for converting a signed to unsigned ensure that this produce correct results for all inputs (including INT_MIN).

    With that, nearly everything else can deal with an unsigned number. Personally, I also prefer to generate the result in order instead of generating in reverse, then reversing it. One fairly simple way to do that is with recursion, with each step first generating previous numerals (if any), then adding its own numeral to the end of the string. I’d have the recursive function deal only with an unsigned type (as produced above). Of course, like nearly everything that manipulates data in a buffer in C, you should also pass the maximum buffer length for it to use, to prevent buffer overruns. For the sake of generality, I’ve also made it accept the base for the conversion as a parameter instead of always assuming base 10.

    Then I’d have a small wrapper function that puts in a — if the input is negative, invokes the function above with the absolute value of the input, and terminates the string after the internal function returns.

    This should also make it pretty trivial to write a utoa that handles unsigned inputs — it would be like itoa without the code to deal with negative numbers. As a minor refinement, I’d probably also make iabs and itoa_internal static functions to minimize the chances of them interfering with other names.

    It is probably bad practice to use ‘unsigned’ to implicitly refer to ‘unsigned int’. If I remember correctly, this is one of the things the C committee will make obsolete in future language standards. The best is of course to use the C99 int types from stdint.h (uint8_t, uint16_t etc) if C99 is available. Also, I don’t see why you would use recursion for this, a plain for loop will both be faster and easier to read. – Lundin 22 ноя. 11 2011-11-22 10:57:50

    @Lundin: Why would it be bad practice? Do you think somebody might think it referred to a nonexistent unsigned float type? I can’t imagine the committee changing this — it would gain nothing, and break huge amounts of code. In this case, the types for ‘stdint.h’ would be detrimental. I used recursion because I’ve yet to see an iterative version that was nearly as clean. «Recursion => slow» has been obsolete for a decade or more. – Jerry Coffin 22 ноя. 11 2011-11-22 11:57:27

    I’m not sure from where I heard that it may become obsolete, but anyway, there’s no reason why you can’t type out 3 more letters just in case, it isn’t that big an effort and makes the code clearer. stdint.h could actually improve the code further — if you know the size of an int, then you can tell whether the [len] parameter is valid or not, if you know that int is 16 bits, then len shouldn’t be longer than 5 letters + 1 null. – Lundin 22 ноя. 11 2011-11-22 12:26:34

    I don’t see how recursion could be optimized by the compiler and still C standard-compliant? A function call is a sequence point and all side effects must be complete before the function is called. With all the side effects in place, I don’t see how the compiler could unroll the recursion on its own? Also, if it _is_ standard-compliant, mustn’t it be tail recursion if the compiler should have any chance at all of optimizing it? I suspect whether the compiler is allowed/able to do this is highly language-dependent. – Lundin 22 ноя. 11 2011-11-22 12:42:15

    IMO, it does not make the code any clearer. Do you also think there’s some improvement from replacing ‘int x;’ with ‘auto signed int x;’? If so, why? If not, why should one use defaults but not the other? Faster recursion is a result of hardware improvements (branch prediction, on-chip return stack, on-chip stack). – Jerry Coffin 22 ноя. 11 2011-11-22 15:43:38

    As far as the types go, I see two obvious problems: first, it would be silly to reject a call just because the type *could* hold a value too large for the buffer. Second, these allow the user to specify the base, so (to use your example) that 16-bit integer *could* require up to 17 characters. – Jerry Coffin 22 ноя. 11 2011-11-22 16:00:35

    Or you can use the mathematical definition of ‘abs()’; ‘sqrt(pow(val, 2))’. – motoku 15 мар. 15 2015-03-15 02:42:01

    @MotokoKusanagi: I suppose you could, but I doubt you’d want to—it’s likely to be slower and less accurate than most others. – Jerry Coffin 15 мар. 15 2015-03-15 04:23:25

    Just some general idea about the code (without any effort to create a better algorithm).

    First of all, I agree with @Jeff, if there is a library for that use it. You don’t have to maintain it and everybody will know what the code does.

    So, code. I would use longer variable names:

    I prefer one declaration per line because it’s easier to read and find the type of variables.

    It looks cool but hard to maintain. Just some questions:

    • Why is it here?
    • Is it intentionally = (and not == )?
    • Why isn’t it in a line before?

    If you have to maintain this code these kind of question could be hurt. So, I would write

    The questions are the in the while loop:

    Finally, I guess there is a potential buffer overflow if the caller pass too small char array to the function.

    Создан 21 ноя. 11 2011-11-21 22:44:10 palacsint

    Good comments. There is nothing gained by merging several rows into one, that’s just obfuscation and makes the code less readable. – Lundin 22 ноя. 11 2011-11-22 10:39:15

    Ссылка на основную публикацию
    Adblock
    detector