Array indexing vs. pointers...

Walter Bright bright at Data-IO.COM
Tue Oct 4 04:17:23 AEST 1988


In article <3105 at hubcap.UUCP> rwberry at hubcap.UUCP (Robert W Berry) writes:
>From article <836 at proxftl.UUCP>, by bill at proxftl.UUCP (T. William Wells):
>> In article <607 at ardent.UUCP> mec at ardent.UUCP (Michael Chastain) writes:
>    I've been programming for YEARS, and if it's not a professional trade
>secret, I'd love it if you would summarize your "coding practices" and
>email them or post them.
>Like you I spend a great deal of my time
>optimizing code for other people, and I have yet to see more than a
>20-25% improvment (even over BAD code.)  

Here's some of the things I do:
    o	Organize complicated if statements so the result of the calculation
	is known by evaluating it as little as possible. For instance,
		if (a && b && c)
			...
	organize such that if a is easy to evaluate and usually FALSE, put
	it first.
    o	Replace stuff like,
		if (a)
			x = b;
		else
			x = c;
	with,
		x = a ? b : c;
	Many compilers generate better code for the latter.
    o	Replace stuff like,
		x = (a == 0) ? 1 : 0;
	with,
		x = (a == 0);
	I know it's obvious, but I see it all the time!
    o	Use the ^ operator because many times,
		a = !a;
	should really be,
		a ^= 1;
    o	Avoid things like,
		a %= 4;
	Replace with,
		a &= 3;
    o	In fact, avoid !, / and % like the plague.
    o	Organize control flow such that the most common cases go straight
	through, this is most important for pipelined machines.
    o	I gag when I see things like,
		a = strlen("asdf") + 1;
	instead of,
		a = sizeof("asdf");
	The strlen case above was even printed in a magazine recently to
	'prove' that assembler was better than C!
    o	Combine printfs,
		printf("aksdf aksjdhf kahdf jhdsfhj\n");
		printf(" asdkljfhkajshdf djfh kjahsdfkja h\n");
	Convert to,
		printf("aksdf aksjdhf kahdf jhdsfhj\n\
		 asdkljfhkajshdf djfh kjahsdfkja h\n");
    o	Try to improve the 'locality' of operations, i.e. move calculations
	as close as possible to the point where they are used. This helps
	most compilers to utilize registers better.
    o	Replace int variables with unsigned where possible. This tells the
	optimizer that the variable can never be negative, making certain
	optimizations possible.
    o	Put the most frequently accessed member of a struct first, so the
	offset is 0.
    o	Use char arrays instead of int arrays where possible. Adjust other
	arrays so that the size of the array elements are a power of 2.
	(Making the address calculation a simple shift.)
    o	Avoid struct function parameters and return values.
    o	Avoid bit fields, most especially signed ones.
    o	Replace sequences of if..else if... with a switch.
    o	Use realloc instead of malloc/free pairs. Use calloc instead of
	malloc followed by zeroing each member.
    o	Think about replacing trivial functions with a macro.

Floating point code offers more opportunities:
    o	Replace floats with doubles (to avoid the conversion).
    o	Try very hard to replace divides with other operations, as in:
		x / 10
	with:
		x * .1
    o	Use functions like ldexp and frexp as much as possible.
    o	See if some calculations can be done using integer math.
    o	Use temporaries to eliminate all common subexpressions.
    o	Reorganize expressions to make the best use of compile-time
	constant folding, since the compiler is not allowed to do that.

And finally:
	Try looking at the assembler output for your favorite function.
	You might be surprised!

Most of these are probably obvious to you. But I have seen all of the
above repeatedly, and have even noticed it myself in going over my own
code. Also, of course, all of the above are judgement calls, and they
are not universally applicable.



More information about the Comp.lang.c mailing list