help on tutorial 14

If you are new to OS Development, plan on spending some time here first before going into the other forums.

Moderator:Moderators

Post Reply
bunkdeath
Posts:1
Joined:Tue Jul 27, 2010 7:05 am
help on tutorial 14

Post by bunkdeath » Tue Jul 27, 2010 6:18 pm

Hello all,

Can you please make me understand the file "stdarg.h".
I guess it is for the arguments passed for DebugPrintf().
I didn't get how it takes each argument.

Here is the code for easy.

Code: Select all

#ifndef __STDARG_H
#define	__STDARG_H
//****************************************************************************
//**
//**    [FILE NAME]
//**    - [FILE DESCRIPTION]
//**
//****************************************************************************
//============================================================================
//    INTERFACE REQUIRED HEADERS
//============================================================================

#include <va_list.h>

//============================================================================
//    INTERFACE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
//============================================================================

#ifdef __cplusplus
extern "C"
{
#endif

/* width of stack == width of int */
#define	STACKITEM	int

/* round up width of objects pushed on stack. The expression before the
& ensures that we get 0 for objects of size 0. */
#define	VA_SIZE(TYPE)					\
	((sizeof(TYPE) + sizeof(STACKITEM) - 1)	\
		& ~(sizeof(STACKITEM) - 1))

/* &(LASTARG) points to the LEFTMOST argument of the function call
(before the ...) */
#define	va_start(AP, LASTARG)	\
	(AP=((va_list)&(LASTARG) + VA_SIZE(LASTARG)))

/* nothing for va_end */
#define va_end(AP)

#define va_arg(AP, TYPE)	\
	(AP += VA_SIZE(TYPE), *((TYPE *)(AP - VA_SIZE(TYPE))))

#ifdef __cplusplus
}
#endif

//============================================================================
//    INTERFACE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
//============================================================================
//============================================================================
//    INTERFACE STRUCTURES / UTILITY CLASSES
//============================================================================
//============================================================================
//    INTERFACE DATA DECLARATIONS
//============================================================================
//============================================================================
//    INTERFACE FUNCTION PROTOTYPES
//============================================================================
//============================================================================
//    INTERFACE OBJECT CLASS DEFINITIONS
//============================================================================
//============================================================================
//    INTERFACE TRAILING HEADERS
//============================================================================
//****************************************************************************
//**
//**    END [FILE NAME]
//**
//****************************************************************************

#endif



User avatar
Mike
Site Admin
Posts:465
Joined:Sat Oct 20, 2007 7:58 pm
Contact:

Re: help on tutorial 14

Post by Mike » Fri Jul 30, 2010 3:51 am

Hello,

DebugPrintf is modeled off of printf() in the series to make debugging a little easier. They both use the same variable argument list functionality.

This one is a bit tricky. Please feel free to ask if there are any questions.

Code: Select all

/* width of stack == width of int */
#define   STACKITEM   int
Each element pushed or popped off the stack is 4 bytes or a multiple of 4 bytes, or the sizeof(int). This is STACKITEM.

Code: Select all

/* round up width of objects pushed on stack. The expression before the
& ensures that we get 0 for objects of size 0. */
#define   VA_SIZE(TYPE)               \
   ((sizeof(TYPE) + sizeof(STACKITEM) - 1)   \
      & ~(sizeof(STACKITEM) - 1))
Because a stack item can be multiple 4 bytes in size, VA_SIZE is used to find the real size on the stack of an object. This is done by rounding up the sizeof(object_data_type) so its a multiple of 4 (STACKITEM).

For example, if you call VA_SIZE(obj) where obj is a structure containing an int (4 bytes) and 1 char (1 byte), VA_SIZE would return 8. Because VA_SIZE rounds objects up to the number of 4 byte stack entries the object would be in, finding arguments in a variable argument list becomes easy.

Because parameters are always passed on the stack, all we need to know is the address of the parameter right before the variable argument list of the function. This is done in va_start(AP,LASTARG). AP is a va_list type, which is just an unsigned char*. LASTARG is the name of the last argument right before the variable argument list in the function.

Code: Select all

#define   va_start(AP, LASTARG)   \
   (AP=((va_list)&(LASTARG) + VA_SIZE(LASTARG)))
This macro uses & to get the address of LASTARG, this is its address on the stack. It converts it to a va_list pointer and locates the first argument in the variable argument list. Because of VA_SIZE, this becomes a simple addition now. It sets the va_list byte pointer so it now points to the first parameter in the variable argument list.

Code: Select all

#define va_arg(AP, TYPE)   \
   (AP += VA_SIZE(TYPE), *((TYPE *)(AP - VA_SIZE(TYPE))))
Here, AP points to the previous (or first) parameter on the stack. To get the next parameter, all we need to do is move our stack pointer, AP, to point to the next type. Similar with va_start, thanks to VA_SIZE this becomes a simple addition in the (AP += VA_SIZE(TYPE part. A problem however is that now AP points to the parameter after the parameter that we are wanting to get. So, we do (AP - VA_SIZE(TYPE), convert it to TYPE* and return the data it points to.

I hope this clarifies what they do and how they work.
Lead Programmer for BrokenThorn Entertainment, Co.
Website: http://www.brokenthorn.com
Email: webmaster@brokenthorn.com

Post Reply