Как C обрабатывает целочисленные литералы с ведущими нулями, и как насчет atoi? - PullRequest
8 голосов
/ 02 ноября 2009

Когда вы создаете целое число с ведущими нулями, как с этим справиться? Различно ли это для разных версий C?

В моем случае они, кажется, просто отбрасываются (но, может, именно это и делает printf?)

#include <stdio.h>

int main() {
    int a = 005;
    printf("%i\n", a);
    return 0;
}

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

Ответы [ 8 ]

32 голосов
/ 02 ноября 2009

Лидирующие нули указывают, что число выражено в восьмеричном , или основании 8; таким образом, 010 = 8. Добавление дополнительных ведущих нулей не имеет никакого эффекта; как и следовало ожидать в математике, x + 0 * 8 ^ n = x; нет значения для изменения, делая его представление длиннее.

Вы часто видите это в режимах файлов UNIX; 0755 фактически означает 7 * 8 ^ 2 + 5 * 8 + 5 = 493; или с такими масками, как 0022 = 2 * 8 + 2 = 10.

atoi(nptr) определен как эквивалент strtol(nptr, (char **) NULL, 10), за исключением того, что он не обнаруживает ошибки - как таковой, atoi() всегда использует десятичную (и, следовательно, игнорирует начальные нули). strtol(nptr, anything, 0) выполняет следующие действия:

Строка может начинаться с произвольной количество пустого пространства (как определено isspace(3)), за которым следует один необязательный знак '+' или '-'. Если база ноль или 16, строка может затем включает префикс "0x" и номер будет прочитано в базе 16; в противном случае нулевое основание принимается за 10 (десятичное число) если следующий символ не '0', в в этом случае оно принимается за 8 (восьмеричное).

Так что он использует те же правила, что и компилятор C.

7 голосов
/ 02 ноября 2009

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

192.168.010.073

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

Единственное, что хуже, чем неудачное использование C старших нулей для создания восьмеричных чисел, это обработка в Javascript ведущих нулей до иногда восьмеричное число (число восьмеричное, если остальные цифры в порядке - меньше 8 - десятичное в противном случае). В Javascript (017 == 15), но (018 == 18).

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

0t10  (ocTal 8)
0k17  (oKtal 15)

Но я на 35 лет опоздал с моим предложением.

7 голосов
/ 02 ноября 2009

Будь осторожен!

В этом утверждении 005 является восьмеричной константой.

int a = 005;

В этом случае это не имеет значения, потому что восьмеричная восьмизначная константа имеет то же значение, что и эквивалентная десятичная константа, но в C: 015 != 15

Независимо от того, выражается ли целочисленный литерал в восьмеричном, десятичном или шестнадцатеричном формате, после его анализа компилятором он просто обрабатывается как значение. То, как целое число выводится через printf, зависит только от его типа, его значения и спецификаторов формата (и активной локали).

5 голосов
/ 02 ноября 2009

Число с начальным нулем означает восьмеричное кодирование во всех версиях C. Итак, 011 == 9 == 0x9.

Octal - система нумерации, основанная на 8 (вместо 10 для десятичной или 16 для шестнадцатеричной). Так 011 == 1*8 + 1, 013 == 1*8 + 3 и т. Д.

3 голосов
/ 02 ноября 2009

Вы должны попробовать:

int a = 5;
printf("%03i\n", a);

0 означает «заполнение нулями», 3 - желаемую длину вывода.

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

2 голосов
/ 01 февраля 2019

Число с начальным 0 обозначает, что число является восьмеричным числом. Он называется Целочисленные литералы . Вы также можете использовать 0b для обозначения двоичного числа , для шестнадцатеричного числа это 0x или 0X. Вам не нужно ничего писать для десятичных . Смотрите код ниже.

#include<stdio.h>

int main()
{
    int binary = 0b10;
    int octal=010;
    int decimal = 10;
    int hexa = 0x10;
    printf("%d %d %d %d\n", octal, decimal, hexa, binary);
}

Для получения дополнительной информации посетите tutorialspoint .

1 голос
/ 02 ноября 2009

Целые числа не имеют «ведущих нулей», а 5 - это 5, вы можете написать его строковое представление с начальным 0, если хотите, для этого у вас есть модификаторы printf.

0 голосов
/ 02 ноября 2009

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

Ведущие нули связаны исключительно со строковым представлением целого числа. Для печати с ведущими нулями используйте «% 03d». Это обеспечит длину поля 3.

Как правило, "% d" будет печатать целое число символов x и ширину с начальными пробелами. "% 0 d" сделает то же самое, но дополнит начальные нули.

...