# Bug in sprintf?

**URL:** <https://www.ruby-forum.com/t/bug-in-sprintf/65495>\
**Category:** Ruby\
**Created:** [August 18, 2006, 6:39pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495 "2006-08-18T18:39:49Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 18, 2006, 6:39pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/1 "2006-08-18T18:39:49Z")

</div>

All,

Why does this fail?

irb(main):009:0\> sprintf("%d", ‘08’)  
ArgumentError: invalid value for Integer: “08”  
from (irb):9:in `sprintf’  
from (irb):9

I assume it’s because the 08 is being as an octal number prior to being  
changed to a decimal. 01 - 07 work fine, 09 breaks.

But I’m telling sprintf to interpret it as decimal, so why can’t I have  
leading zeroes?

Please explain to me how this is expected behavior.

Thanks,  
Wes

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 18, 2006, 7:00pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/2 "2006-08-18T19:00:50Z")

</div>

Wes G. wrote:

> I assume it’s because the 08 is being as an octal number prior to being  
> changed to a decimal. 01 - 07 work fine, 09 breaks.

Because 8 isn’t an octal number. 0-7 are octal.

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 18, 2006, 7:04pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/3 "2006-08-18T19:04:03Z")

</div>

William C. wrote:

> Wes G. wrote:
> 
> > I assume it’s because the 08 is being as an octal number prior to being  
> > changed to a decimal. 01 - 07 work fine, 09 breaks.
> 
> Because 8 isn’t an octal number. 0-7 are octal.

-slaps self- Think before you reply, William.

On second thought, this -does- seem wrong. It doesn’t matter if you  
tell it to be decimal, octal or hex, it all comes up with an error on 08  
and 09, and not 00 to 07.

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 18, 2006, 7:05pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/4 "2006-08-18T19:05:57Z")

</div>

William C. wrote:

> William C. wrote:
> 
> > Wes G. wrote:
> > 
> > > I assume it’s because the 08 is being as an octal number prior to being  
> > > changed to a decimal. 01 - 07 work fine, 09 breaks.
> > 
> > Because 8 isn’t an octal number. 0-7 are octal.
> 
> -slaps self- Think before you reply, William.
> 
> On second thought, this -does- seem wrong. It doesn’t matter if you  
> tell it to be decimal, octal or hex, it all comes up with an error on 08  
> and 09, and not 00 to 07.

Last time, I swear.  
[http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/145509](http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/145509) Says  
that it IS trying to be octal because the 0 in front means that. (Why  
it means that, I don’t know.)

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 18, 2006, 7:24pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/5 "2006-08-18T19:24:01Z")

</div>

removed\_email\_address@domain.invalid wrote:

> On Sat, 19 Aug 2006, Wes G. wrote:
> 
> > All,
> > 
> > Why does this fail?
> > 
> > irb(main):009:0\> sprintf("%d", ‘08’)  
> > ArgumentError: invalid value for Integer: “08”  
> > from (irb):9:in `sprintf’  
> > from (irb):9  
> > […]
> 
> > But I’m telling sprintf to interpret it as decimal, so why can’t I have  
> > leading zeroes?
> > 
> > Please explain to me how this is expected behavior.  
> > […]  
> > because:  
> > […]  
> > ruby uses ‘Integer(s)’ to convert strings to ints and  
> > […]  
> > Kernel#Integer  
> > […]  
> > If _arg_ is a +String+, leading radix indicators (+0+, +0b+, and  
> > +0x+) are honored.  
> > […]  
> > so it’s expected, documented, and consistent with c.

It is not expected, nor documented, because the documentation of sprintf  
says:  
d | Convert argument as a decimal number.

…which is very explicit in that the argument will be interpreted as a  
decimal number, not octal.

Greetings.

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 18, 2006, 7:09pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/6 "2006-08-18T19:09:00Z")

</div>

On Sat, 19 Aug 2006, Wes G. wrote:

> changed to a decimal. 01 - 07 work fine, 09 breaks.
> 
> But I’m telling sprintf to interpret it as decimal, so why can’t I have  
> leading zeroes?
> 
> Please explain to me how this is expected behavior.
> 
> Thanks,  
> Wes

because:

```
 harp:~ > cat a.c
 main(){ char s[42]; int r = sprintf (s, "%d", 07); printf ("%d: 

```

\<%s\>\n", r, s); }

```
 harp:~ > gcc a.c
 harp:~ > a.out
 1: <7>

 harp:~ > cat a.c
 main(){ char s[42]; int r = sprintf (s, "%d", 08); printf ("%d: 

```

\<%s\>\n", r, s); }

```
 harp:~ > gcc a.c
 a.c: In function `main':
 a.c:1: numeric constant contains digits beyond the radix

```

ruby uses ‘Integer(s)’ to convert strings to ints and

```
 harp:~ > ri Kernel.Integer
 --------------------------------------------------------- 

```

Kernel#Integer  
Integer(arg) =\> integer  
------------------------------------------------------------------------  
Converts _arg_ to a +Fixnum+ or +Bignum+. Numeric types are  
converted directly (with floating point numbers being  
truncated).  
If _arg_ is a +String+, leading radix indicators (+0+, +0b+,  
and  
+0x+) are honored. Others are converted using +to\_int+ and  
+to\_i+.  
This behavior is different from that of +String#to\_i+.

```
         Integer(123.999) #=> 123
         Integer("0x1a") #=> 26
         Integer(Time.new) #=> 1049896590

 harp:~ > ruby -e' Integer "07" '

 harp:~ > ruby -e' Integer "08" '
 -e:1:in `Integer': invalid value for Integer: "08" (ArgumentError)
         from -e:1

```

so it’s expected, documented, and consistent with c.

a good pattern to use is:

harp:~ \> ruby -e’ atoi = lambda{|s| Integer(s) rescue  
%r/(\d+)/.match(s)[1].to\_i rescue raise ArgumentError, s};  
p(atoi[“08”]); p(atoi[“fubar”]) ’  
8  
-e:1: fubar (ArgumentError)  
from -e:1

because simply falling back on to\_i yields

harp:~ \> ruby -e’ atoi = lambda{|s| Integer(s) rescue s.to\_i};  
p(atoi[“08”]); p(atoi[“fubar”]) ’  
8  
0

regards.

-a

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 18, 2006, 7:27pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/7 "2006-08-18T19:27:19Z")

</div>

Thanks for the comprehensive response.

Well, I can’t really argue with the C implementation, of course…

BUT

it feels like if I declare my intent to interpret the sprintf input as a  
_decimal_ number with %d (there’s a %o if I wanted octal), that is  
should allow for leading zeroes.

My intent in writing sprintf("%d", ‘08’) is to say take the string 08  
and turn it into the number 8.

It isn’t to say here’s an octal number, please convert it to decimal for  
me. If I think the string is octal, I’ll use %o for that.

So in the spirit of what the user expects, I still think this smells  
bad.

Feel free to convince me otherwise.

Thanks again,  
Wes

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 18, 2006, 7:28pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/8 "2006-08-18T19:28:05Z")

</div>

What Carlos said 😉

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 18, 2006, 7:42pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/9 "2006-08-18T19:42:04Z")

</div>

On 8/18/06, Wes G. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> My intent in writing sprintf(“%d”, ‘08’) is to say take the string 08  
> Thanks again,  
> Wes

As I see it, there are two separate things: WHAT number you want to  
print, and HOW you want it print.

The latter one is specified by the format string.  
The former one is specified by argument.

Think of sprintf(“%d”, 0x1234) or sprintf(“%x”, 123).

And it happens to be that ‘08’ is in this case the same as 08 and that  
is invalid octal number. QED. 😉

Jano

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 18, 2006, 7:53pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/10 "2006-08-18T19:53:08Z")

</div>

Carlos wrote:

> It is not expected, nor documented, because the documentation of sprintf  
> says:  
> d | Convert argument as a decimal number.
> 
> …which is very explicit in that the argument will be interpreted as a  
> decimal number, not octal.

I disagree on that. %d tells sprintf to expect an Integer as the  
corresponding argument. Being given a String instead it tries to convert  
it by calling Kernel#Integer. This fails for the reasons already  
metioned.

Greetings, Matthias

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 18, 2006, 8:03pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/11 "2006-08-18T20:03:07Z")

</div>

Carlos [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

> …which is very explicit in that the argument will be interpreted as  
> a decimal number, not octal.

I think that the problem here is that ruby is performing two  
conversions, and the sprintf documentation only mentions one of them.

When you use ‘%d’ in a sprintf(), ruby does a conversion of the  
argument to an Integer using Kernel#Integer and then does the  
conversion of the Integer to a portion of the output string as  
documented.

Similarly, when you use %f in a sprintf(), ruby does a conversion of  
the argument using Kernel#float and then does the conversion from  
Float to part of the output string as documented.

So, we have:

sprintf(“%d”,‘08’) ==\> ArgumentError  
sprintf(“%d”,‘8’) ==\> “8”  
sprintf(“%d”,‘08’.to\_i) ==\> “8”  
sprintf(“%f”,‘08’) ==\> “8.000000”

I think that if you’re hitting this quirk in actual code, your code  
needs so .to\_i dropped in a few places. I’m actually surprised ruby  
does those String=\>Integer conversions at all.

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 18, 2006, 8:26pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/12 "2006-08-18T20:26:29Z")

</div>

I’ll buy that. I did know that my input was a String so I am implicitly  
asking for a conversion to occur.

Thanks for the discussion - it helps a lot.

Wes

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 18, 2006, 9:42pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/13 "2006-08-18T21:42:20Z")

</div>

On Aug 18, 2006, at 8:00 PM, Daniel M. wrote:

> When you use ‘%d’ in a sprintf(), ruby does a conversion of the  
> argument to an Integer using Kernel#Integer and then does the  
> conversion of the Integer to a portion of the output string as  
> documented.

How did you figure that out? I started at sprintf.c and browsed a bit  
around from rb\_f\_sprintf on, but I think I was in the wrong path. Or  
is it the call to rb\_str\_to\_inum equivalent to Kernel#Integer?

– fxn

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 18, 2006, 8:27pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/14 "2006-08-18T20:27:10Z")

</div>

Wes G. wrote:

> My intent in writing sprintf("%d", ‘08’) is to say take the string 08  
> and turn it into the number 8.
> 
> It isn’t to say here’s an octal number, please convert it to decimal for  
> me. If I think the string is octal, I’ll use %o for that.
> 
> So in the spirit of what the user expects, I still think this smells  
> bad.
> 
> Feel free to convince me otherwise.

Consider it this way:

The format character (%d) is a way to know how the values collected  
will be displayed. The values, in this case arguments to %d, are not  
intrepreted (necessarily) at the same time as the format characters and  
therefor are seperate entities. Taking any [legal] value and passing it  
to %d will result in a decimal number printed out.  
However, the parsing aspect is entirely different. There is no format  
that says: ‘this is how to interpret me’ - other than the syntax.  
If you take that away you create ambiguities. If the syntax is longer  
how to distinguish a value, it must be explicitly tied to a format  
string/character.

Imagine the confusion when you try to  
#define FORTY\_TWO\_HEX %x 2a  
#define FORTY\_TWO\_OCT %o 52  
#define FORTY\_TOW\_DEC %d 42  
(Since the two are now linked, you need the format characters. Or  
should it be %x 42, %o 42 … you get the idea)

instead of  
#define FORTY\_TWO\_HEX 0x2a  
#define FORTY\_TWO\_OCT 052  
#define FORTY\_TWO\_DEC 42

While it may be easy/convenient to suggest allowing a format character  
determine a value, it breaks when not in a specific setting.

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 18, 2006, 9:48pm UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/15 "2006-08-18T21:48:21Z")

</div>

Wes G. wrote:

> it feels like if I declare my intent to interpret the sprintf input as a  
> _decimal_ number with %d (there’s a %o if I wanted octal), that is  
> should allow for leading zeroes.

Declare your intent by doing ‘08’.to\_i(10) instead. In fact, declare  
your intent in the first place that way.

Expecting sprintf to be automagical the way you expect out of two  
incompatible, but perfectly valid interpretations isn’t much to rely on.  
Code everything explicitly and you’ll get predictable results.

I’ll join the club of people wondering why the String-\>Integer coercion  
is happening in the first place.

David V.

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 19, 2006, 12:30am UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/16 "2006-08-19T00:30:36Z")

</div>

Carlos wrote:

> says:  
> d | Convert argument as a decimal number.
> 
> …which is very explicit in that the argument will be interpreted as a  
> decimal number, not octal.

The string of characters is interpreted as a decimal number IF IT IS  
one. Since you started it with a zero, it’s octal.

Hal

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 19, 2006, 12:27am UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/17 "2006-08-19T00:27:34Z")

</div>

William C. wrote:

> Last time, I swear.  
> [http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/145509](http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/145509) Says  
> that it IS trying to be octal because the 0 in front means that. (Why  
> it means that, I don’t know.)

This comes from C, and is at least 30 years old.

The zero looks like an O, which stands for Octal.

Be glad it’s not Pascal, where 377B is an octal  
number (because B looks like an 8).

Hal

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 19, 2006, 12:30am UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/18 "2006-08-19T00:30:36Z")

</div>

Wes G. wrote:

> My intent in writing sprintf("%d", ‘08’) is to say take the string 08  
> and turn it into the number 8.
> 
> It isn’t to say here’s an octal number, please convert it to decimal for  
> me. If I think the string is octal, I’ll use %o for that.
> 
> So in the spirit of what the user expects, I still think this smells  
> bad.
> 
> Feel free to convince me otherwise.

I see your point. But most things in Ruby that are stolen from C  
behave JUST like the C counterparts. In fact, in many cases they  
are just wrappers.

So I can understand why you don’t like it. But my understanding  
is that you should blame C.

Hal

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 19, 2006, 12:42am UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/19 "2006-08-19T00:42:37Z")

</div>

Wes G. wrote:

> I’ll buy that. I did know that my input was a String so I am implicitly  
> asking for a conversion to occur.
> 
> Thanks for the discussion - it helps a lot.

Actually I failed to take that into account, so what I said  
was half nonsense. 🙂

Hal

---

<div class="post-metadata">

**Author:** ![weyus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7ab992/32.png) [@weyus](https://www.ruby-forum.com/u/weyus)\
**Post date:** [August 19, 2006, 3:23am UTC](https://www.ruby-forum.com/t/bug-in-sprintf/65495/20 "2006-08-19T03:23:56Z")

</div>

Carlos wrote:

> For that conversion, #to\_i could have been used as well, and then ‘09’ would  
> be interpreted as decimal 9. Why should I expect my string to be passed  
> through Integer() before formatting? That is not documented.

Why would you pass a string to something that expects a number  
anyway?

Hal

[Next page](https://www.ruby-forum.com/t/bug-in-sprintf/65495.md?page=2)
