Googles appar
Huvudmeny

Post a Comment On: cbloom rants

"08-22-10 - AutoPrintf v1"

10 Comments -

1 – 10 of 10
Anonymous Anonymous said...

Are you sure it's not allowed by the standard? I thought that the design WAS that the va_list is an iterator, not just a list. But I've never read the relevant parts of the standard.

August 23, 2010 at 12:52 PM

Blogger cbloom said...

" Are you sure it's not allowed by the standard? I thought that the design WAS that the va_list is an iterator, not just a list. But I've never read the relevant parts of the standard. "

Eh.. I read somewhere that you aren't allowed to do that, but I haven't actually read the standard.

.. reading it now ..

actually it looks like it's fine. The standard doesn't clearly say that when you pass the va_list through it will act like the remaining args, it just says you can pass it.

But it also says that after passing it, your copy of the va_list is invalidated and you must immediately call va_end to stop your iteration, then restart from the beginning.

So I could do that but it's a bit annoying.

August 23, 2010 at 1:06 PM

Blogger cbloom said...

See

http://www.opengroup.org/onlinepubs/009695399/basedefs/stdarg.h.html

August 23, 2010 at 1:06 PM

Anonymous Anonymous said...

God I hate that kind of spec writing. Anyway, the description of how ap advances and the cross-function comments seem to mean (though hard to be sure through spec speak) that it's supposed to do the right thing. This seems strongly the implication of va_copy, which lets you copy the current state and pass one or the other to another function, and then pick up again where you left off. It's probably legit to let the called function return you the va_list and continue where it left off, but it's unclearly written given the way they talk about multiple functions.

August 24, 2010 at 6:08 AM

Blogger cbloom said...

It's not even clear to me from the spec what va_copy is supposed to do after you've called va_arg. Does it copy the whole list, or just the portion of the list you are now pointing at?

I mean that spec is just terrible. It's not actually restrictive enough to give the implementers much freedom, but it's also not clear or generous enough to gaurantee the clients the functionality they need.

Which is why I get so pissed off at standards wonks. In practice I know how va_list works on every real platforms, and I know what I can and can't do, and that is a way more useful "de facto spec" than what's written.

August 24, 2010 at 9:00 AM

Anonymous Anonymous said...

va_copy just copies the pointer--it gives you a copy of the iterator into the same data.

i think.

August 24, 2010 at 5:33 PM

Blogger castano said...

Hmm... what happend with my previous comment? Is it awaiting moderation or was it sent directly to /dev/null?

Anyway, the problem with va_copy is that in the x64 calling convention some arguments are always passed by registers, even with variadic functions. GCC handles that using a structure holding the registers and the stack pointer; va_list is a pointer to that structure, so in order to save the state you have to use va_copy. Here's an explanation of how that works on msvc and why it does not require va_copy.

August 24, 2010 at 11:35 PM

Blogger cbloom said...

Yeah I looked at the implementation of va_arg on x64 MSVC and saw it was just doing stack pointer stepping so figured they had to be copying the args somewhere. I think their solution to do it inside the callee is nice.

I might do the GCC port some day. Or somebody who actually cares about GCC compatibility can do it.

August 25, 2010 at 8:22 AM

Blogger Thatcher Ulrich said...

"if ( 0 ) ;"

You are cracking me up :)

Did you do that because it makes the "else if" clauses line up nicely, or because it's faster on PS3?

August 25, 2010 at 5:50 PM

Blogger cbloom said...

Lol. It's actually because that code is all autogen'ed and it was just easier to not generate a special case for the first if.

see:


template < typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10 >
inline String autoToString( const char *fmt, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10 )
{
autoFormatInfo fmtInfo = GetAutoFormatInfo(fmt);
if ( fmtInfo.autoArgI )
{
String newFmt = ChangeAtoS(fmt,fmtInfo);
if ( 0 ) ;
else if ( fmtInfo.autoArgI == 1 ) return autoToString(newFmt.CStr(), ToString(arg2).CStr(),arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10);
else if ( fmtInfo.autoArgI == 2 ) return autoToString(newFmt.CStr(), arg2,ToString(arg3).CStr(),arg4,arg5,arg6,arg7,arg8,arg9,arg10);
else if ( fmtInfo.autoArgI == 3 ) return autoToString(newFmt.CStr(), arg2,arg3,ToString(arg4).CStr(),arg5,arg6,arg7,arg8,arg9,arg10);
else if ( fmtInfo.autoArgI == 4 ) return autoToString(newFmt.CStr(), arg2,arg3,arg4,ToString(arg5).CStr(),arg6,arg7,arg8,arg9,arg10);
else if ( fmtInfo.autoArgI == 5 ) return autoToString(newFmt.CStr(), arg2,arg3,arg4,arg5,ToString(arg6).CStr(),arg7,arg8,arg9,arg10);
else if ( fmtInfo.autoArgI == 6 ) return autoToString(newFmt.CStr(), arg2,arg3,arg4,arg5,arg6,ToString(arg7).CStr(),arg8,arg9,arg10);
else if ( fmtInfo.autoArgI == 7 ) return autoToString(newFmt.CStr(), arg2,arg3,arg4,arg5,arg6,arg7,ToString(arg8).CStr(),arg9,arg10);
else if ( fmtInfo.autoArgI == 8 ) return autoToString(newFmt.CStr(), arg2,arg3,arg4,arg5,arg6,arg7,arg8,ToString(arg9).CStr(),arg10);
else if ( fmtInfo.autoArgI == 9 ) return autoToString(newFmt.CStr(), arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,ToString(arg10).CStr());
else return autoPrintf_BadAutoArgI(fmt,fmtInfo);
}

if ( fmtInfo.numPercents == 0 ) return ToString(fmt) + autoToString(arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10);
else if ( fmtInfo.numPercents == 1 ) return StringPrintf(fmt,arg2) + autoToString(arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10);
else if ( fmtInfo.numPercents == 2 ) return StringPrintf(fmt,arg2,arg3) + autoToString(arg4,arg5,arg6,arg7,arg8,arg9,arg10);
else if ( fmtInfo.numPercents == 3 ) return StringPrintf(fmt,arg2,arg3,arg4) + autoToString(arg5,arg6,arg7,arg8,arg9,arg10);
else if ( fmtInfo.numPercents == 4 ) return StringPrintf(fmt,arg2,arg3,arg4,arg5) + autoToString(arg6,arg7,arg8,arg9,arg10);
else if ( fmtInfo.numPercents == 5 ) return StringPrintf(fmt,arg2,arg3,arg4,arg5,arg6) + autoToString(arg7,arg8,arg9,arg10);
else if ( fmtInfo.numPercents == 6 ) return StringPrintf(fmt,arg2,arg3,arg4,arg5,arg6,arg7) + autoToString(arg8,arg9,arg10);
else if ( fmtInfo.numPercents == 7 ) return StringPrintf(fmt,arg2,arg3,arg4,arg5,arg6,arg7,arg8) + autoToString(arg9,arg10);
else if ( fmtInfo.numPercents == 8 ) return StringPrintf(fmt,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9) + autoToString(arg10);
else if ( fmtInfo.numPercents == 9 ) return StringPrintf(fmt,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10);
else return autoPrintf_TooManyPercents(fmt,fmtInfo);
};

August 25, 2010 at 6:10 PM

You can use some HTML tags, such as <b>, <i>, <a>

This blog does not allow anonymous comments.

Comment moderation has been enabled. All comments must be approved by the blog author.

You will be asked to sign in after submitting your comment.