Highly efficient string reversal code

C

CBFalconer

pete said:
Rosario wrote:
.... snip ...


*(p1 + 1) is undefined for a zero length string.

Nit picking time.

No it isn't. It is if that string is stored in a char array
smaller than array of two chars.
 
V

vippstar

... snip ...



Nit picking time.

No it isn't. It is if that string is stored in a char array
smaller than array of two chars.

Nit picking time :)
Yes it is,

char foo[2];
foo[0] = 0;
reverse(foo);
 
A

Antoninus Twink

You know I really had to look hard at this to understand it. Horrible
variables names almost purposely made "no standard" as far as C around
the world goes for such a function. Unnecessary length check.
Unnecessary size_t. Multiple assignments on one line making perusal
with a debugger almost impossible.

Yep - CBF is a living master-class in anti-style.
Much nicer IMO:

#include <string.h>

char * my_strrev(char *s){
char t;
char *e = s+strlen(s)-1;
while(e>s){
t = *s;
*s++ = *e;
*e-- = t;
}
}

Much nicer! Of course the "UB" that got the regs in a state will never
be a problem in the real world.

As efficiency was a concern for the OP, it might be worth dealing
specially with the favorable case when both the string length and its
starting location match up with the machine's natural alignment, so that
one can use only aligned accesses.

For example, on a 32-bit machine this might be more efficient (though of
course only profiling will tell for sure):



#define SWAP32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))

char *my_strrev(char *s)
{
size_t len = strlen(s);
if(((unsigned long) s & len & 0x11)==0) {
/* s aligned on 4-byte boundary, and length a multiple of 4 */
unsigned *start = (unsigned *) s;
unsigned *end = start + (len>>2) - 1;
unsigned temp;
while(end > start) {
temp = SWAP32(*start);
*start++ = SWAP32(*end);
*end-- = temp;
}
}
else {
/* use generic string reverser */
}
return s;
}
 
B

Ben Bacarisse

As efficiency was a concern for the OP, it might be worth dealing
specially with the favorable case when both the string length and its
starting location match up with the machine's natural alignment, so that
one can use only aligned accesses.

For example, on a 32-bit machine this might be more efficient (though of
course only profiling will tell for sure):



#define SWAP32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))

char *my_strrev(char *s)
{
size_t len = strlen(s);
if(((unsigned long) s & len & 0x11)==0) {
/* s aligned on 4-byte boundary, and length a multiple of 4 */
unsigned *start = (unsigned *) s;
unsigned *end = start + (len>>2) - 1;
unsigned temp;
while(end > start) {
temp = SWAP32(*start);
*start++ = SWAP32(*end);
*end-- = temp;
}
}
else {
/* use generic string reverser */
}
return s;
}

I presume you share Richard's preference for interactive debugging?
 
A

Antoninus Twink

I presume you share Richard's preference for interactive debugging?

Hmm? Apart from the fact that a | has wrongly become a & in this line...

....(and as a result of the correction extra parentheses are needed), I
don't see any obvious bug.
 
B

Ben Bacarisse

Antoninus Twink said:
Hmm? Apart from the fact that a | has wrongly become a & in this line...


...(and as a result of the correction extra parentheses are needed), I
don't see any obvious bug.

Nothing happens when len == 4.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,142
Latest member
arinsharma
Top