If you write your equivalency tests in C "backwards", your are much less likely to accidentally use = where you meant ==. For instance:
if (VALUE == variable)
{
/* ... */
}
rathern than:
if (variable == VALUE)
{
/* ... */
}
because the 1st method will generate an error on the compile if
VALUE is not a modifiable lvalue (a variable into which you can
assign a value). Using the 2nd method, you could accidentally write
if (variable = VALUE) and the mistake may go unnoticed, for a
while anyway.
Did you know that sizeof is an ANSI C operator, not a function or macro?
Therefore, it doesn't require parentheses, as seems to be the common usage.
Note that the parentheses are required only if a type is used as the operand
to sizeof, as in sizeof (int); it can be thought of
as taking the sizeof a cast. However, this construct is almost
never required because you nearly always have a properly typed data
object or pointer to use instead, as in:
{
size_t size;
my_type something;
size = sizeof something; /* look ma, no parentheses! */
}
#include <stdlib.h> /* malloc */
{
my_type *pointer;
pointer = malloc(sizeof *pointer);
/* ... */
}
If you declare your arrays properly, you can determine the number of elements, and perform some operation on each element, without ever referring explicitly to the size used to dimension the array. This method has the advantage that, if the size or type of the arrray element changes, only the defintion of the array needs to change. For example:
{
my_type array[100];
for (i = 0; i < (sizeof array / sizeof *array); i++)
{
/* ... */
}
}
gotos in C are OK. There, I said it and I mean it. Don't be
afraid to use any C language feature that may be useful to you.
There are situations, especially in exception handling,
in which goto is the only easy way out. One rule-of-thumb to
be sure you're not using goto where another construct would work
better is, "Never goto backwards" or "Always goto
forward" in the code. This rule will keep you from using goto
for loop-control, where for or while are more
appropriate.
For example:
BOOLEAN do_stuff(void)
{
if (!do_something()) goto error_label;
if (!do_something_else()) goto error_label;
if (!do_something_also())
{
error_label:
clean_up_everything();
return FALSE;
}
return TRUE;
}
One of the simplest ways to conditionally compile out a portion of code is
to use the #if preprocessor directive. This method has the
advantage over "commenting out" code that #if directives can be
nested. Also, the original behavior can be restored by changing just one
character.
Here's an example:
#include <unistd.h> /* sleep */ /* ... */ #if 0 /* don't do this code! */ while (1); #else /* do this code instead ... */ sleep(1); #endifIf you decide to reinstate the original portion of code, simply change the directive to #if 1.
The whence shell builtin can do some neat tricks. Since it prints an absolute
path to a file, it can be used as short-hand for the absolute path, when
combined with sub-shell expansion.
For instance, say you
want to do an ls -l of some executable in your path:
$ ls -l $(whence some_executuble)Or, you're working on a script that is in your path, and want to edit it:
$ vi $(whence some_script)
When you refer to a variable in the shell, it's much safer to use this syntax:
${my_variable?}
than simply:
$my_variableThe curly brace characters guarantee that the variable name is bounded, so that the shell won't misinterpret the name if it occurs amid a string, as in:
${TERM?}INFO
Also, the ? indicates that the shell should abort execution of
the command or script if the variable is null or not set.
Did you know that the Korn shell can do base conversions? Using the shells typeset keyword to create an integer variable, you can specify the base. Constants can be pre-pended with base# to indicate their base.
Say you wanted to find the decimal and binary representation from 0xFFF:
$ typeset -i10 num=16#FFF # assign 0xFFF into a base 10 integer variable $ print $num 4095 $ typeset -i2 num # convert the variable to base 2 $ print $num 2#111111111111 $
Some shells have a cutesy little feature that if you try to execute a directory as if it were a command, the shell will make that your current working directory, ie. chdir(2).
While ksh doesn't explicitly have this feature, as the result of someone in comp.unix.shell asking if it's possible, I wrote this hack:
# trap to automatically cd to directory if you try to execute it
if [[ -t 0 ]]
then
trap 'dir=$(fc -nl -0 -0) && dir=${dir# } && [[ -d ${dir?} ]] && cd ${dir?}' ERR
# ^ Hey! this is a tab!
fi
Here's an explanation: