How does C handle integer literals with leading zeros, and what about "atoi"?
Asked Answered
S

9

11

When you create an integer with leading zeros, how does C handle it? Is it different for different versions of C?

In my case, they just seem to be dropped (but maybe that is what printf does?):

#include <stdio.h>

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

I know I can use printf to pad with 0s, but I am just wondering how this works.

Stoltzfus answered 2/11, 2009 at 13:31 Comment(2)
Added "literal" because in binary, every positive int has a leading zero.Discretionary
Except for unsigned ints greater than UINT_MAX/2 :)Bandit
B
38

Leading zeros indicate that the number is expressed in octal, or base 8; thus, 010 = 8. Adding additional leading zeros has no effect; just as you would expect in math, x + 0*8^n = x; there's no change to the value by making its representation longer.

One place you often see this is in UNIX file modes; 0755 actually means 7*8^2+5*8+5 = 493; or with umasks such as 0022 = 2*8+2 = 10.

atoi(nptr) is defined as equivalent to strtol(nptr, (char **) NULL, 10), except that it does not detect errors - as such, atoi() always uses decimal (and thus ignores leading zeros). strtol(nptr, anything, 0) does the following:

The string may begin with an arbitrary amount of white space (as determined by isspace(3)) followed by a single optional '+' or '-' sign. If base is zero or 16, the string may then include a "0x" prefix, and the number will be read in base 16; otherwise, a zero base is taken as 10 (decimal) unless the next character is '0', in which case it is taken as 8 (octal).

So it uses the same rules as the C compiler.

Bandit answered 2/11, 2009 at 13:34 Comment(3)
Thanks, maybe this a different question, but with atoi or strtol without a base of zero, what happens with leading zeros?Stoltzfus
I understand perfectly now, thank you! I'm sure this is in all my basic C books, just didn't stick in my head :-PStoltzfus
I was wondering the same thing... Looks like clang++ and g++ will both return "19" for strtol("0019",NULL,10), at least.Stonedeaf
M
9

The fact that a leading zero indicates a number is octal is something that's often forgotten. I've seen it cause confusion several times, such as when someone tried to input an IP address using a nice, regular format for the octets:

192.168.010.073

and the parser interpreted the last 2 octets as octal numbers.

The only thing worse than C's unfortunate use of leading zeros to make a number octal is Javascript's handling of leading zeros to sometimes make a number octal (the number is octal if the rest of the digits are OK - less than 8 - decimal otherwise). In Javascript, (017 == 15) but (018 == 18).

I'd rather there be an error; actually I'd rather drop octal literal support altogether. At least use a more in-your-face prefix, like maybe

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

But I'm about 35 years too late with my proposal.

Monarchist answered 2/11, 2009 at 15:35 Comment(1)
Following the lead of hex (0x) and binary (0b), use 0o as a prefix fo octal. However, although 0X and 0B cause no problems, the scope for confusion with 0O as a prefix argues against changing the status quo.Norven
S
8

Be careful!

In this statement 005 is an octal constant.

int a = 005;

In this case it doesn't matter because a single digit octal constant has the same value as the equivalent decimal constant but in C: 015 != 15

Whether an integer literal is expressed in octal, decimal or hexadecimal, once it is parsed by the compiler it is just treated as a value. How an integer is output via printf depends only on its type, its value and the format specifiers (and the active locale).

Sesqui answered 2/11, 2009 at 13:35 Comment(1)
@behrooz: it prints out decimal 5, because decimal and octal 5 are the same value. This isn't true for 010 and 10. Print out the first and you get 8 (the decimal string representation of binary 1000 or octal 010). Print out the second and you get 10 (binary 1010 or octal 012).Busywork
R
5

A number with a leading zero means octal encoding in all versions of C. So 011 == 9 == 0x9.

Octal is a numbering system based on 8 (instead of 10 for decimal or 16 for hex). So 011 == 1*8 + 1, 013 == 1*8 + 3, etc.

Redouble answered 2/11, 2009 at 13:35 Comment(0)
D
3

You should try:

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

0 means "pad with zeroes", 3 is the desired length of output.

Edit: Sorry, I've read your question too quickly - now I see you've asked about something completely different. However I'll leave this as is, as it might be helpful for someone else.

Donela answered 2/11, 2009 at 13:45 Comment(0)
M
2

A number with leading 0 denoted that the number is an octal number. It's called Integer Literals. You can also use 0b for denoting binary number, for hexadecimal number it is 0x or 0X. You don't need to write any thing for decimal. See the code bellow.

#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);
}

For more information visit tutorialspoint.

Marder answered 1/2, 2019 at 15:3 Comment(0)
M
1

Integers don't have "leading zeros" a 5 is a 5, you may write its string representation with leading 0 if you want, for that you have the printf modifiers.

Monosepalous answered 2/11, 2009 at 13:33 Comment(2)
I didn't say that it was the same. Obviously his intentions were to add 0s, not using octal.Monosepalous
It wasn't so obvious to me since he indicated that he already knew he could pad with 0's on output. Obviously, integers do have leading 0's when you want to express them in octal notation.Busywork
C
1

In your particular case, the zeroes are being dropped by printf. All leading zeroes are stripped out by the compiler except for the initial zero which causes your compiler to treat the integer as octal. For 005, both the octal and decimal representations are the same and should not bother you but still, it's asking for trouble unless you specifically meant the octal representation.

Leading zeroes have to do purely with the string representation of the integer. To print with leading zeroes, use "%03d". This will ensure a field length of 3.

In general, "%<x>d" will print an integer x characters wide and will pad with leading spaces. "%0<x>d" will do the same thing but will pad with leading zeroes.

Confectioner answered 2/11, 2009 at 13:39 Comment(1)
-1, the leading zeros are not "dropped by printf". Literals in the source are converted to a binary representation (with no concept of leading zeros) by the compiler. printf has no idea how the value was represented in the source.Anaemia
M
0

Background

Numbers starting with "0" are in base 8, so called octal numbers, using digits 0-7. Just as numbers starting with "0x" are in base 16, hexadecimal numbers, using digits 0-9 and A-F (case insensitive, a-f).

As every octal digit represents 3 bits, 027 (9 bits) is probably used to represent 8 bits, a byte. Its decimal value = 0.8² + 2.8¹ + 7.8° = 23.

027 == 23 == 0x17

And last but not least 028 would give a compile error: not a valid number.

Nowadays hexadecimal numbers are ubiquitous, as they fit a byte into exactly 2 hex digits.

However in the old Unix time hardware had words other 8 bits too. Also note that in Unix/Linux file rights of user, group and others form a triplet of r/w/x, so old school 0777 (all rights) is still in use.

Monah answered 19/8, 2023 at 7:53 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.