Understanding va_list
Writing your own function that uses a va_list is really easy!
But first, let’s identify what a va_list is.
Think about the printf() C function.
printf(“Hello there! I like the numbers %d, %d and %d\n\n\n”, 1, 3, 7);
Obviously the output of that function call would be:
Hello there! I like the numbers 1, 3 and 7
But the key point here is, the printf() function can accept a VARYING NUMBER OF ARGUMENTS. That’s because it uses a va_list.
If you look at the signature for printf(), it looks like this:
int printf( char * format, … );
So the argument list for printf() has 2 main things:
char * format – a regular string
and a second special argument, … (3 dots, just like that)
… is called an “ellipsis”, and it means, in plain English: “any number of optional arguments can go here.”
So somehow, in the innermost bowels of printf(), is some sticky code that somehow retrieves each one of the the list of args you’re passing in, in the place of the “…”.
Cool! So is it possible for us to write our functions that have their own sticky code that can process a set of VARIABLE ARGUMENTS???
YES YOU CAN. And its actually simple!
An example:
#include
#include
int addThemAll( int numargs, ... )
{
// So this function can accept a variable number
// of arguments. No (practically speaking) limits.
// RULES you must know in order to be able to use "..." in one of your
// own functions:
//
// 1) The ... MUST appear exactly as ...
// It cannot be "..." (with the quotes),
// '...', or anything else weird.
//
// 2) The ... __MUST GO LAST__ IN THE ARGUMENT LIST
//
// 3) THERE MUST BE AT LEAST ONE MANDATORY, NON-OPTIONAL ARGUMENT,
// THAT COMES BEFORE THE ...
// We'll be using these macros here:
/*
va_list va_start va_end va_arg
*/
// All of the above va_* things are actually special MACROS,
// exclusively defined for us to use when working with
// _V_ariable _A_rgument lists.
// FIRST, we create a POINTER that will be used
// to point to the first element of the VARIABLE
// ARGUMENT LIST.
va_list listPointer;
// Currently, listPointer is UNINITIALIZED, however,
// SO, now we make listPointer point to
// the first argument in the list
va_start( listPointer, numargs );
// Notice that numargs is the LAST MANDATORY ARGUMENT
// that the addThemAll() function takes.
// By "LAST MANDATORY ARGUMENT", I mean 'numargs'
// is the last argument to the addThemAll() function
// JUST BEFORE the "..."
// NEXT, we're going to start to actually retrieve
// the values from the va_list itself.
// THERE IS A CATCH HERE. YOU MUST KNOW THE
// DATA TYPE OF THE DATA YOU ARE RETRIEVING
// FROM THE va_list. In this example, I'm assuming
// they're all ints, but you could always pass a format
// string that lets you know the types.
int sum = 0;
for( int i = 0 ; i < numargs; i++ )
{
// GET an arg. YOU MUST KNOW
// THE TYPE OF THE ARG TO RETRIEVE
// IT FROM THE va_list.
int arg = va_arg( listPointer, int );
printf( " The %dth arg is %d\n", i, arg );
sum += arg;
}
printf("--");
printf("END OF ARGUMENT LIST\n\n");
// FINALLY, we clean up by saying
// va_end(). Don't forget to do this
// BEFORE the addThemAll() function returns!
va_end( listPointer );
printf("The total sum was %d\n\n", sum);
return sum;
}
int main()
{
// Try it out.
printf("Calling 'addThemAll( 3, 104, 29, 46 );' . . .\n");
addThemAll( 3, 104, 29, 46 );
printf("Calling 'addThemAll( 8, 1, 2, 3, 4, 5, 6, 7, 8 );' . . .\n");
addThemAll( 8, 1, 2, 3, 4, 5, 6, 7, 8 );
return 0;
}
Monday, June 21, 2010
Enum
These fall into the category of ‘half baked’. They aren't proper enumerated types, as in Pascal, and only really serve to help you reduce the number of #define statements in your program. They look like this:
enum e_tag{
a, b, c, d=20, e, f, g=20, h
}var;Just as with structures and unions, the e_tag is the tag, and var is the definition of a variable.
The names declared inside the enumeration are constants with int type. Their values are these:
a == 0
b == 1
c == 2
d == 20
e == 21
f == 22
g == 20
h == 21so you can see that, in the absence of anything to the contrary, the values assigned start at zero and increase. A specific value can be given if you want, when the increase will continue one at a time afterwards; the specific value must be an integral constant (see later) that is representable in an int. It is possible for more than one of the names to have the same value.
The only use for these things is to give a better-scoped version of this:
#define a 0
#define b 1
/* and so on */It's better scoped because the declaration of enumerations follows the standard scope rules for C, whereas #define statements have file scope.
Not that you are likely to care, but the Standard states that enumeration types are of a type that is compatible with an implementation-defined one of the integral types. So what? For interest's sake here is an illustration:
enum ee{a,b,c}e_var, *ep;The names a, b, and c all behave as if they were int constants when you use them; e_var has type enum ee and ep is a pointer to enum ee. The compatibility requirement means that (amongst other implications) there will be an integral type whose address can be assigned to ep without violating the type-compatibility requirements for pointers.
enum e_tag{
a, b, c, d=20, e, f, g=20, h
}var;Just as with structures and unions, the e_tag is the tag, and var is the definition of a variable.
The names declared inside the enumeration are constants with int type. Their values are these:
a == 0
b == 1
c == 2
d == 20
e == 21
f == 22
g == 20
h == 21so you can see that, in the absence of anything to the contrary, the values assigned start at zero and increase. A specific value can be given if you want, when the increase will continue one at a time afterwards; the specific value must be an integral constant (see later) that is representable in an int. It is possible for more than one of the names to have the same value.
The only use for these things is to give a better-scoped version of this:
#define a 0
#define b 1
/* and so on */It's better scoped because the declaration of enumerations follows the standard scope rules for C, whereas #define statements have file scope.
Not that you are likely to care, but the Standard states that enumeration types are of a type that is compatible with an implementation-defined one of the integral types. So what? For interest's sake here is an illustration:
enum ee{a,b,c}e_var, *ep;The names a, b, and c all behave as if they were int constants when you use them; e_var has type enum ee and ep is a pointer to enum ee. The compatibility requirement means that (amongst other implications) there will be an integral type whose address can be assigned to ep without violating the type-compatibility requirements for pointers.
Union
A Union is like a structure, except that each
element shares the same memory. Thus in this
example, the coords and about members overlap.
Note that the setting of about[2] to 'X' CORRUPTS
the float in this demonstration.
In a practical use, a variable such as un_type
(provided but not used in this example) would be
set up to indicate which particular use is being
made of the union
*/
typedef union {
float coords[3];
char about[20];
} assocdata;
typedef struct {
char *descript;
int un_type;
assocdata alsostuff;
} leaf;
int main() {
leaf oak[3];
int i;
printf ("Hello World\n");
for (i=0; i<3; i++) {
oak[i].descript = "A Greeting";
oak[i].un_type = 1;
oak[i].alsostuff.coords[0] = 3.14;
}
oak[2].alsostuff.about[2] = 'X';
for (i=0; i<3; i++) {
printf("%s\n",oak[i].descript);
printf("%5.2f\n",oak[i].alsostuff.coords[0]);
}
}
/* Sample of output from this program
[trainee@daisy cd07]$ ./union
Hello World
A Greeting
3.14
A Greeting
3.14
A Greeting
3.39
[trainee@daisy cd07]$
element shares the same memory. Thus in this
example, the coords and about members overlap.
Note that the setting of about[2] to 'X' CORRUPTS
the float in this demonstration.
In a practical use, a variable such as un_type
(provided but not used in this example) would be
set up to indicate which particular use is being
made of the union
*/
typedef union {
float coords[3];
char about[20];
} assocdata;
typedef struct {
char *descript;
int un_type;
assocdata alsostuff;
} leaf;
int main() {
leaf oak[3];
int i;
printf ("Hello World\n");
for (i=0; i<3; i++) {
oak[i].descript = "A Greeting";
oak[i].un_type = 1;
oak[i].alsostuff.coords[0] = 3.14;
}
oak[2].alsostuff.about[2] = 'X';
for (i=0; i<3; i++) {
printf("%s\n",oak[i].descript);
printf("%5.2f\n",oak[i].alsostuff.coords[0]);
}
}
/* Sample of output from this program
[trainee@daisy cd07]$ ./union
Hello World
A Greeting
3.14
A Greeting
3.14
A Greeting
3.39
[trainee@daisy cd07]$
Friday, June 18, 2010
Pointers to functions
A useful technique is the ability to have pointers to functions. Their declaration is easy: write the declaration as it would be for the function, say
int func(int a, float b);
and simply put brackets around the name and a * in front of it: that declares the pointer. Because of precedence, if you don't parenthesize the name, you declare a function returning a pointer:
/* function returning pointer to int */
int *func(int a, float b);
/* pointer to function returning int */
int (*func)(int a, float b);
Once you've got the pointer, you can assign the address of the right sort of function just by using its name: like an array, a function name is turned into an address when it's used in an expression. You can call the function using one of two forms:
(*func)(1,2);
/* or */
func(1,2);
The second form has been newly blessed by the Standard. Here's a simple example.
#include
#include
void func(int);
main(){
void (*fp)(int);
fp = func;
(*fp)(1);
fp(2);
exit(EXIT_SUCCESS);
}
void
func(int arg){
printf("%d\n", arg);
}
int func(int a, float b);
and simply put brackets around the name and a * in front of it: that declares the pointer. Because of precedence, if you don't parenthesize the name, you declare a function returning a pointer:
/* function returning pointer to int */
int *func(int a, float b);
/* pointer to function returning int */
int (*func)(int a, float b);
Once you've got the pointer, you can assign the address of the right sort of function just by using its name: like an array, a function name is turned into an address when it's used in an expression. You can call the function using one of two forms:
(*func)(1,2);
/* or */
func(1,2);
The second form has been newly blessed by the Standard. Here's a simple example.
#include
#include
void func(int);
main(){
void (*fp)(int);
fp = func;
(*fp)(1);
fp(2);
exit(EXIT_SUCCESS);
}
void
func(int arg){
printf("%d\n", arg);
}
Arrays as Pointers
Using an array name as a pointer
An array name is really a pointer to the first element of the array.
For example, the following is legal.
int b[100]; // b is an array of 100 ints.
int* p; // p is a pointer to an int.
p = b; // Assigns the address of first element of b to p.
p = &b[0]; // Exactly the same assignment as above.
Array name is a const pointer
When you declare an array, the name is a pointer, which cannot be altered. In the previous example, you could never make this assignment.
p = b; // Legal -- p is not a constant.
b = p; // ILLEGAL because b is a constant, altho the correct type.
Pointer arithmetic
"Meaningful" arithmetic operations are allowed on pointers.
Add or subtract integers to/from a pointer. The result is a pointer.
Subtract two pointers to the same type. The result is an int.
Multiplying, adding two pointers, etc. don't make sense.
Pointer addition and element size
When you add an integer to a pointer, the integer is multiplied by the element size of the type that the pointer points to.
// Assume sizeof(int) is 4.
int b[100]; // b is an array of 100 ints.
int* p; // p is a a pointer to an int.
p = b; // Assigns address of first element of b. Ie, &b[0]
p = p + 1; // Adds 4 to p (4 == 1 * sizeof(int)). Ie, &b[1]
Equivalence of subscription and dereference
Because of the way C/C++ uses pointers and arrays, you can reference an array element either by subscription or * (the unary dereference operator).
int b[100]; // b is an array of 100 ints.
int* p; // p is a a pointer to an int.
p = b; // Assigns address of first element of b. Ie, &b[0]
*p = 14; // Same as b[0] = 14
p = p + 1; // Adds 4 to p (4 == 1 * sizeof(int)). Ie, &b[1]
*p = 22; // Same as b[1] = 22;
Example - Two ways to add numbers in an array
The first uses subscripts, the second pointers. They are equivalent.
int a[100];
. . .
int sum = 0;
for (int i=0; i<100; i++) {
sum += a[i];
}
int a[100];
. . .
int sum = 0;
for (int* p=a; p
sum += *p;
}
An array name is really a pointer to the first element of the array.
For example, the following is legal.
int b[100]; // b is an array of 100 ints.
int* p; // p is a pointer to an int.
p = b; // Assigns the address of first element of b to p.
p = &b[0]; // Exactly the same assignment as above.
Array name is a const pointer
When you declare an array, the name is a pointer, which cannot be altered. In the previous example, you could never make this assignment.
p = b; // Legal -- p is not a constant.
b = p; // ILLEGAL because b is a constant, altho the correct type.
Pointer arithmetic
"Meaningful" arithmetic operations are allowed on pointers.
Add or subtract integers to/from a pointer. The result is a pointer.
Subtract two pointers to the same type. The result is an int.
Multiplying, adding two pointers, etc. don't make sense.
Pointer addition and element size
When you add an integer to a pointer, the integer is multiplied by the element size of the type that the pointer points to.
// Assume sizeof(int) is 4.
int b[100]; // b is an array of 100 ints.
int* p; // p is a a pointer to an int.
p = b; // Assigns address of first element of b. Ie, &b[0]
p = p + 1; // Adds 4 to p (4 == 1 * sizeof(int)). Ie, &b[1]
Equivalence of subscription and dereference
Because of the way C/C++ uses pointers and arrays, you can reference an array element either by subscription or * (the unary dereference operator).
int b[100]; // b is an array of 100 ints.
int* p; // p is a a pointer to an int.
p = b; // Assigns address of first element of b. Ie, &b[0]
*p = 14; // Same as b[0] = 14
p = p + 1; // Adds 4 to p (4 == 1 * sizeof(int)). Ie, &b[1]
*p = 22; // Same as b[1] = 22;
Example - Two ways to add numbers in an array
The first uses subscripts, the second pointers. They are equivalent.
int a[100];
. . .
int sum = 0;
for (int i=0; i<100; i++) {
sum += a[i];
}
int a[100];
. . .
int sum = 0;
for (int* p=a; p
sum += *p;
}
Thursday, June 17, 2010
IRC Class - Basic IRC Commands
Just as you are able to surf the net with a few tricks to help make things easier, IRC is very similar. Below you will find some of the more common IRC commands that we use often.
/join
Type /join #channelname -- to join a channel of your choice
Example: /join #bossmom
What it looks like:
[18:44] *** Now talking in #beginner
--Op-- bossmom has joined the channel
[18:44] *** Topic is 'Beginner's Help/Chat Channel....All Are Welcome Here!! ®© [ENGLISH]'
[18:44] *** Set by X on Sun Jul 23 16:10:34
/me
The /me is an action message.
Type /me 'does anything'
Example: /me waves hello
What it looks like:
* bossmom waves hello
/msg
Type /msg nickname (message) to start a private chat.
Example: /msg puddytat Hey tat, how are you?
What it looks like:
-> *puddytat* Hey tat, how are you?
/nick
/nick changes your nickname
Example: type /nick newnickname (limit 9 characters)
What it looks like: I typed /nick luv2quilt
*** bossmom is now known as luv2quilt
/notice
A notice is used to send a short message to another person without opening up a private window.
Type /notice nickname (message)
Example: /notice badnick Please change your nickname for this family channel.
What it looks like:
-> -badnick- Please change your nickname for this family channel.
/part
Type /part -- to leave one channel
Type /partall -- to leave all the channels you are in
/ping
Type /ping nickname. What this command does is give you the ping time, or lag time, between you and the person you pinged. Lag can be explained as the amount of time it takes for you to type your message and for others to read your messages. Unfortunately, lag is always a part of IRC, although most times it's not a problem, just a nuisance.
Example: /ping luv2quilt
What it looks like:
[19:04] -> [luv2quilt] PING
[19:04] [luv2quilt PING reply]: 0secs
/query
Similar to the /msg, except it forces a window to pop open.
Type /query nickname (message)
Example: /query Sofaspud^ Sooo....what's new?
What it looks like:
soooo....what's new?
/quit
Type /quit to leave IRC altogether. This disconnects mirc from the server.
Example: /quit Going out for dinner...nite all
What it looks like:
*** Quits: saca (Leaving)
/ignore
Unfortunately, there will be times when you don't want to talk to someone, or else someone may be harassing you.
By typing /ignore nickname 3, you will not receive anymore messages from that person.
Example: /ignore luv2quilt 3
To Unignore them, type /ignore -r luv2quilt 3
What it looks like:
*** Added *!*bossmom@*.dialup.netins.net to ignore list
*** Removed *!*bossmom@*.dialup.netins.net from ignore list
/whois
Type /whois nickname to see a bit more information about another user. You'll see what server another person is using, or what their ISP is. Pretty helpful when you don't recognize a nickname that wants to chat. You may recognize the IP, (Internet Protocol) and then feel more comfortable carrying on a conversation. You'll also be able to see what other channels a person is in, which might be a good indicator if you really want to talk with them or not.
Example: /whois bossmom
What it looks like:
luv2quilt is bossmom@elwo-01-094.dialup.netins.net * Enjoy the Journey........
luv2quilt on @#bossmom
luv2quilt using Seattle.WA.US.Undernet.org the time for school is during a recession.
luv2quilt has been idle 18secs, signed on Sun Jul 23 18:47:26
luv2quilt End of /WHOIS list.
/chat
This opens up a DCC/CHAT window to another user. What's nice about these is that you can continue to chat even if you get disconnected from your server.
Word of Caution: Do NOT accept dcc/chats nor dcc/gets from anyone that you don't know.
Type /chat nickname.
Example: /chat oddjob^
What it looks like:
Chat with oddjob^
Waiting for acknowledgement...
/help
There's one more very helpful command, and probably the one you'll use a lot when first starting out. In fact, I still use it quite a lot, and that's the built-in help menu of mIRC.
Type /help, you'll see the the mIRC Help Menu open up. You can do a search from there, or you can type /help topic. Either way, a TON of information at your fingertips.
Example: /help Basic IRC Commands
/join
Type /join #channelname -- to join a channel of your choice
Example: /join #bossmom
What it looks like:
[18:44] *** Now talking in #beginner
--Op-- bossmom has joined the channel
[18:44] *** Topic is 'Beginner's Help/Chat Channel....All Are Welcome Here!! ®© [ENGLISH]'
[18:44] *** Set by X on Sun Jul 23 16:10:34
/me
The /me is an action message.
Type /me 'does anything'
Example: /me waves hello
What it looks like:
* bossmom waves hello
/msg
Type /msg nickname (message) to start a private chat.
Example: /msg puddytat Hey tat, how are you?
What it looks like:
-> *puddytat* Hey tat, how are you?
/nick
/nick changes your nickname
Example: type /nick newnickname (limit 9 characters)
What it looks like: I typed /nick luv2quilt
*** bossmom is now known as luv2quilt
/notice
A notice is used to send a short message to another person without opening up a private window.
Type /notice nickname (message)
Example: /notice badnick Please change your nickname for this family channel.
What it looks like:
-> -badnick- Please change your nickname for this family channel.
/part
Type /part -- to leave one channel
Type /partall -- to leave all the channels you are in
/ping
Type /ping nickname. What this command does is give you the ping time, or lag time, between you and the person you pinged. Lag can be explained as the amount of time it takes for you to type your message and for others to read your messages. Unfortunately, lag is always a part of IRC, although most times it's not a problem, just a nuisance.
Example: /ping luv2quilt
What it looks like:
[19:04] -> [luv2quilt] PING
[19:04] [luv2quilt PING reply]: 0secs
/query
Similar to the /msg, except it forces a window to pop open.
Type /query nickname (message)
Example: /query Sofaspud^ Sooo....what's new?
What it looks like:
soooo....what's new?
/quit
Type /quit to leave IRC altogether. This disconnects mirc from the server.
Example: /quit Going out for dinner...nite all
What it looks like:
*** Quits: saca (Leaving)
/ignore
Unfortunately, there will be times when you don't want to talk to someone, or else someone may be harassing you.
By typing /ignore nickname 3, you will not receive anymore messages from that person.
Example: /ignore luv2quilt 3
To Unignore them, type /ignore -r luv2quilt 3
What it looks like:
*** Added *!*bossmom@*.dialup.netins.net to ignore list
*** Removed *!*bossmom@*.dialup.netins.net from ignore list
/whois
Type /whois nickname to see a bit more information about another user. You'll see what server another person is using, or what their ISP is. Pretty helpful when you don't recognize a nickname that wants to chat. You may recognize the IP, (Internet Protocol) and then feel more comfortable carrying on a conversation. You'll also be able to see what other channels a person is in, which might be a good indicator if you really want to talk with them or not.
Example: /whois bossmom
What it looks like:
luv2quilt is bossmom@elwo-01-094.dialup.netins.net * Enjoy the Journey........
luv2quilt on @#bossmom
luv2quilt using Seattle.WA.US.Undernet.org the time for school is during a recession.
luv2quilt has been idle 18secs, signed on Sun Jul 23 18:47:26
luv2quilt End of /WHOIS list.
/chat
This opens up a DCC/CHAT window to another user. What's nice about these is that you can continue to chat even if you get disconnected from your server.
Word of Caution: Do NOT accept dcc/chats nor dcc/gets from anyone that you don't know.
Type /chat nickname.
Example: /chat oddjob^
What it looks like:
Chat with oddjob^
Waiting for acknowledgement...
/help
There's one more very helpful command, and probably the one you'll use a lot when first starting out. In fact, I still use it quite a lot, and that's the built-in help menu of mIRC.
Type /help, you'll see the the mIRC Help Menu open up. You can do a search from there, or you can type /help topic. Either way, a TON of information at your fingertips.
Example: /help Basic IRC Commands
hello everyone
hi everyone:
Nice to meet you !!!! My name is liang wang. I hope we have good time in this class. And have "A" grade.
Nice to meet you !!!! My name is liang wang. I hope we have good time in this class. And have "A" grade.
Subscribe to:
Posts (Atom)