In C, accessing an array index is faster or accessing by pointer is faster? By faster I mean, which one would take less clock cycle. The array is not an constant array.
Explicitly eliminating common subexpressions might work for you. There may be a difference if you are using x86 or RISC architecture and optimizer quality.
When I write a routine which has to run through an array or indexed structure I compute a pointer to the base of the array/structure member and use that to address. The basic case
struct SOMETHING list[100];
int find_something (...)
{
int i;
i=0;
while (i<(sizeof(list)/sizeof(struct SOMETHING)))
{
if (list[i].active && list[i].last_access+60<current_time) return i;
++i;
}
return -1;
}
can be refined to (i e helping the compiler to produce better code):
int find_something (...)
{
int i;
struct SOMETHING *pList;
i=0;
while (i<(sizeof(list)/sizeof(struct SOMETHING)))
{
pList=&list[i];
if (pList->active && pList->last_access+60<current_time) return i;
++i;
}
return -1;
}
This is just to illustrate and the simplicity of the code would probably generate the pointer implicitly but if the routine is more complex that might not be the case. Using "list[i]." as in the first example you'd run (on the x86) the risk (RISC haha) of the compiler not having enough registers to generate and store the address once, instead generating it for every single reference. For the x86-case a local variable is necessary to store the pointer and few compilers will create stack variables unless explicitly directed to. On RISC the compiler has lots of registers at its disposal and will usually decide that it is worthwhile to create (and keep) the pointer once for every iteration.
The loop can be refined further:
pList=list;
i=0;
while (i<(sizeof(list)/sizeof(struct SOMETHING)))
{
if (pList->active && pList->last_access+60<current_time) return i;
pList+=1;
++i;
}
This construction is devoid of any address calculation overhead. "pList+=1" (others might prefer "++pList") causes a constant value (equal to the size of an individual row/member) to be added to pList.
And further:
pList=list;
pEndList=&list[sizeof(list)/sizeof(struct SOMETHING)];
while (pList!=pEndList)
{
if (pList->active && pList->last_access+60<current_time) return pList-list;
pList+=1;
}
Which eliminates the index increment and replaces it with one multiplication outside and one division inside the loop (executed just once, in the return construct).
Now before all you don't-optimizers out there start screaming bloody murder my point is that what constructs are acceptable is determined by the size and complexity of the function in which they reside. I would probably not consider this construct in a 300-line function that is complex enough to begin with but in a situation such as the above? If the searches are a significant part of overall processing? If the speed-ups are large enough?
So why not? Pros and cons. It's always pros and cons. Making the best of them. Absolutes? Rarely (if ever).
Simple index operations compile to the same machine code on every compiler I've ever touched. By index is usually recommended for readability.
More complex cases that involve different logic for pointer access vs array indexing need to be examined on a case-by-case basis. If you are in doubt, profile your code - as always.