Archive

Archive for January, 2007

Macro arguments – be careful with them

8 January, 2007 Leave a comment

Debugging applications that has lots of macro()s are considered to be very tough. And it seems that most people prefer to expand macros as blocks with new temporary variables. Let us try to find out why one would not prefer to use the macro arguments directly in their block code. Consider for example a macro that returns the square of a number. Normally, any careful programmer would write the macro as given below:

#define square(a) ((a) * (a))

And yes, what the macro will do is precisely what we would expect of it. The above macro is just perfect as long as what we provide as argument to it is a plain value – like a variable or a constant. For example:

int i = 10;

printf("square : %d\n", square(i));

would print 100 as we had desired. The preprocessed text is just the expression ((i) * (i)). This will continue to go on fine until you start to do some fancy tricks like the following:

int i = 10;

printf("square : %d\n", square(++i));

Obviously, what we had expected was the square of 11 but the one we got was that of 12(for gcc, can change for others). So, how did that happen? Yes.. after preprocessing, your code became ((++i) * (++i)) and according to gcc, the values of i used in the expression is that after doing all the pre-increments in the expression. Since there are 2 pre-increments, the compiler takes the expression as ((12) * (12)).

Apart from the wrong answer we got, another side effect that we have to acknowledge is that the variable i has been incremented twice after calling square(), instead of just once. So, what is the solution for such a situation? Simple, use only dummy variables for computations:

#define square(a) ({ typeof(a) var=(a); var*var; })

so thats it ! you dont need to worry at all about the new variable that you have created above – compilers are intelligent enough to nullify its overhead. Well, so now our problem is solved :-) we can create new ones ;-)

Categories: Programming

The essence of do{ } while(0)

6 January, 2007 Leave a comment

This is something that I’ve been longing to document in my blog. Many times I have wondered why almost all the #define macros in linux kernel is made up of do-while blocks rather than simple {} blocks. The reason is illustrated below:

Consider for example a swap() macro defined in the two different ways as shown below:

#define swap(a,b) { \

typeof(a) tmp; \

tmp=a; a=b; b=tmp; \

}

and

#define swap(a,b) do { \

typeof(a) tmp; \

tmp=a;a=b;b=tmp; \

} while(0)

At a glance both seem to do the same job of creating a new block of code where the variable tmp is created and the values a and b are swapped through it. And they both will work similarly under all circumstances except the following:

if(a<b)

swap(a,b);

else

printf("a is already greater than b\n");

The above code when using the first form of swap() macro will expand as following:

if(a<b)

{

typeof(a) tmp;

tmp=a;a=b;b=tmp;

}

;

else

printf("a is already greater than b\n");

The issue here is that the semicolon (;) that we have put after swap() infact terminates the if block and remains as an empty statement. This causes the else keyword not to be attached to the if block anymore and will cause a compilation error saying that the else keyword is misplaced. huh !

Anyway, good that we got a workaround for this problem, otherwise writing system software would have become a hell :-D . By the way, if you are using gcc, you can use ({ }) blocks as well which would be very much helpful if your macro needs to return some value ;-) – the return value is the last evaluated expression.

Categories: Programming

‘Expect’ as an administration tool

3 January, 2007 Leave a comment

This is an article that I had posted in my livejournal on 6th-May-2006 06:58 pm. I’m trying to migrate the most valuable stuff to wordpress.

Last time we saw how to execute those special system tools(ssh, ftp, su, …) by providing the password through PTYs. But, the problem is that its not easy or ideal at all to write a C program to do such system maintenance or automation tasks. Also, if we need to process the output of the running child program and respond it with dynamic inputs, the task becomes very complicated. Then, the obvious guess would be… right, a script. Today, we’re going to see how ‘Expect’ can be used to do our task with ease.

Expect can be thought of as a tool which can run other programs in a PTY with the knowledge of what to expect from the child program. ie, Expect can be told how to behave towards the child program for its various outputs. And its being done through a script similar to Tcl. Unfortunately, I don’t know Tcl at all, but certainly know how to use expect for my needs. So here’s the code that does what we required when we wrote the last C program – ptymagic.c:

#!/usr/bin/expect

spawn [lrange $argv 0 0] [lrange $argv 1 $argc]

expect {

“Password:” {

expect_user -re “(.*)\n”
send_user “\n”
send “$expect_out(1,string)\r”
exp_continue

}

}

Suppose you name the file as ptymagic, and give execute permission for the same, test it as we did previously:

echo “Your_Root_Password” | ./ptymagic su -c “cat /etc/shadow”

May be it’ll seem slow, but hey, we are here to write maintenance script for the system and not any scientific supercomputing simulations…

best of luck…

Categories: System Administration
Follow

Get every new post delivered to your Inbox.