Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does C Handle Integer Literals with Leading Zeros, and What About atoi?

Tags:

c

literals

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.

like image 563
Kyle Brandt Avatar asked Nov 02 '09 13:11

Kyle Brandt


6 Answers

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.

like image 159
bdonlan Avatar answered Nov 08 '22 09:11

bdonlan


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.

like image 22
Michael Burr Avatar answered Nov 08 '22 09:11

Michael Burr


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).

like image 20
CB Bailey Avatar answered Nov 08 '22 08:11

CB Bailey


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.

like image 33
Agnel Kurian Avatar answered Sep 18 '22 12:09

Agnel Kurian


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.

like image 5
Aaron Digulla Avatar answered Nov 08 '22 08:11

Aaron Digulla


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.

like image 3
madej Avatar answered Nov 08 '22 08:11

madej