Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Glue to Re-define a Bunky Function?

39 views
Skip to first unread message

Modafinil

unread,
Dec 5, 2011, 10:15:54 AM12/5/11
to
Hi,

Some code I'm working with uses the C string library function
strrchr(), but my compiler's implementation works in a non-standard
way. It can't seem to point to a string's first '\0' character with a
call like p = strrchr(dest, '\0');

In preference to altering the original code, I would like to somehow
re-define the function within an associated glue header file.
Something along the lines of:

#define strrchr(a, b) (&a[strlen(a)])
or
#define strrchr(a, b) ((a)+strlen((a)))

Okay, I'm obviously out of my depth here. Can anyone please lend me
some ideas on how to achieve this?

The original function's declaration in string.h is along the lines of:

extern _ARMABI char *strrchr(const char * /*s*/, int /*c*/)
__attribute__((__nonnull__(1)));

TIA
--
comp.lang.c.moderated - moderation address: cl...@plethora.net -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line. Sorry.

Keith Thompson

unread,
Dec 10, 2011, 5:06:18 AM12/10/11
to
Modafinil <vanl...@iinet.net.au> writes:
> Some code I'm working with uses the C string library function
> strrchr(), but my compiler's implementation works in a non-standard
> way. It can't seem to point to a string's first '\0' character with a
> call like p = strrchr(dest, '\0');

How sure are you that your implementation's strrchr() is misbehaving?
What output do you get for this program?

#include <stdio.h>
#include <string.h>
int main(void) {
char *s = "hello";
char *p = strrchr(s, '\0');
if (p == NULL) {
printf("p = NULL\n");
}
else {
printf("p - s = %d\n", (int)(p - s));
}
return 0;
}

It should print "p - s = 5". If it prints something else, you should
submit a bug report. What implementation is it?

> In preference to altering the original code, I would like to somehow
> re-define the function within an associated glue header file.
> Something along the lines of:
>
> #define strrchr(a, b) (&a[strlen(a)])
> or
> #define strrchr(a, b) ((a)+strlen((a)))

If strrchr() is already defined as a macro, you'll need "#undef strrchr"
first.

Both of those definitions ignore the second argument, which will break
any calls to strrchr() with a second argument other than '\0'. And
redefining predefined functions is generally not a great idea anyway.

> Okay, I'm obviously out of my depth here. Can anyone please lend me
> some ideas on how to achieve this?
>
> The original function's declaration in string.h is along the lines of:
>
> extern _ARMABI char *strrchr(const char * /*s*/, int /*c*/)
> __attribute__((__nonnull__(1)));

Why do you need to avoid altering the original code?
"dest + strlen(dest)" is a cleaner way to do the computation anyway.
Or you can try using strchr() rather than strrchr(); it should give
the same result in this case.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Hans-Bernhard Bröker

unread,
Dec 10, 2011, 5:06:48 AM12/10/11
to
On 05.12.2011 16:15, Modafinil wrote:

> Some code I'm working with uses the C string library function
> strrchr(), but my compiler's implementation works in a non-standard
> way. It can't seem to point to a string's first '\0' character with a
> call like p = strrchr(dest, '\0');

One note here: It doesn't make sense to search for such a thing as "a
string's first '\0' character", because by definition, a string contains
exactly one of those.

> In preference to altering the original code, I would like to somehow
> re-define the function within an associated glue header file.

I suspect that's impossible in the general case. You would be causing
undefined behaviour by violating C99 7.1.3p2.

> Something along the lines of:
>
> #define strrchr(a, b) (&a[strlen(a)])
> or
> #define strrchr(a, b) ((a)+strlen((a)))

That redefinition doesn't work for any other 'b' than '\0'. Are you
sure your code can live with that --- forever?

Dag-Erling Smørgrav

unread,
Dec 10, 2011, 5:07:48 AM12/10/11
to
Modafinil <vanl...@iinet.net.au> writes:
> In preference to altering the original code, I would like to somehow
> re-define the function within an associated glue header file.

You can simply provide your own implementation.

DES
--
Dag-Erling Smørgrav - d...@des.no

Jasen Betts

unread,
Dec 10, 2011, 5:08:18 AM12/10/11
to
On 2011-12-05, Modafinil <vanl...@iinet.net.au> wrote:
> Hi,
>
> Some code I'm working with uses the C string library function
> strrchr(), but my compiler's implementation works in a non-standard
> way. It can't seem to point to a string's first '\0' character with a
> call like p = strrchr(dest, '\0');

indeed, "C99" section 7.21.5.5 requires it to treat the terminating null
as part of the string.

> In preference to altering the original code, I would like to somehow
> re-define the function within an associated glue header file.
> Something along the lines of:
>
> #define strrchr(a, b) (&a[strlen(a)])
> or
> #define strrchr(a, b) ((a)+strlen((a)))

this seems right:

#define strrchr(a,b) (b?strrchr(a, b):((char*)a)+strlen(a))

> extern _ARMABI char *strrchr(const char * /*s*/, int /*c*/)
> __attribute__((__nonnull__(1)));

looks like GCC.

Can you get the source of strrchr and fix it? I expect the maintainer
will accept a valid patch, however strrchr is probably written in
assembler so this may not be as simple as it seems.

--
⚂⚃ 100% natural

--- Posted via news://freenews.netfront.net/ - Complaints to ne...@netfront.net ---

Barry Schwarz

unread,
Dec 10, 2011, 5:07:18 AM12/10/11
to
On Mon, 5 Dec 2011 09:15:54 -0600 (CST), Modafinil
<vanl...@iinet.net.au> wrote:

>Hi,
>
>Some code I'm working with uses the C string library function
>strrchr(), but my compiler's implementation works in a non-standard
>way. It can't seem to point to a string's first '\0' character with a
>call like p = strrchr(dest, '\0');

Since a string must contain exactly one '\0' and since that character
will definitely be the last character in the string, your attempt to
call strrchr with the first argument pointing to it is pointless.

Further more, calling strchr or strrchr with a second argument of zero
is a waste. The returned value is guaranteed to str+strlen(str).

You seem to be under the impression that the argument passed to
strrchr should point to the end of the string. This is wrong.

>
>In preference to altering the original code, I would like to somehow
>re-define the function within an associated glue header file.
>Something along the lines of:
>
>#define strrchr(a, b) (&a[strlen(a)])
> or
>#define strrchr(a, b) ((a)+strlen((a)))

Before you start inventing macros, it might be a good idea to show us
some sample code and describe what you want to accomplish.

--
Remove del for email

Kenneth Brody

unread,
Dec 10, 2011, 5:09:02 AM12/10/11
to
On 12/5/2011 10:15 AM, Modafinil wrote:
> Hi,
>
> Some code I'm working with uses the C string library function
> strrchr(), but my compiler's implementation works in a non-standard
> way. It can't seem to point to a string's first '\0' character with a
> call like p = strrchr(dest, '\0');

At first, I was going to say that a string doesn't contain a '\0', but I
decided to check the definition first, and 7.21.5.4p2 says:

The strrchr function locates the last occurrence of c (converted to
a char) in the string pointed to by s. The terminating null character
is considered to be part of the string.

If your implementation "doesn't work" (you don't say what it does), then
it's not a conforming implementation. (If they claim to be, submit a bug
report.)

> In preference to altering the original code, I would like to somehow
> re-define the function within an associated glue header file.
> Something along the lines of:
>
> #define strrchr(a, b) (&a[strlen(a)])
> or
> #define strrchr(a, b) ((a)+strlen((a)))
>
> Okay, I'm obviously out of my depth here. Can anyone please lend me
> some ideas on how to achieve this?
[...]

You could try something like this (*untested*) code:

After the #include <string.h>, add:

inline char *my_strrchr(const char *str,int c)
{
if ( c == '\0' )
return( str + strlen(str) );
else
return( strrchr(str,c) );
}
#define strrchr(str,c) my_strrchr(str,c)

--
Kenneth Brody

Modafinil

unread,
Dec 11, 2011, 12:58:54 AM12/11/11
to
> comp.lang.c.moderated - moderation address: c...@plethora.net -- you must
> have an appropriate newsgroups line in your header for your mail to be seen,
> or the newsgroup name in square brackets in the subject line.  Sorry.

Thanks to everyone for the very valuable tips.

Okay, I understand what my compiler was trying to tell me now, and
have a clearer understanding of how to patch functions with glue
definitions.

#define strrchr(a, b) ((a)+strlen((a)))

This didn't work because the compiler "expected an identifier". My re-
definition '((a)+strlen((a)))
' was unsuitable as it had no function name portion to substitute for
the original 'strrchr' identifier.

Here's a re-definition that does have a function name portion, that
being the identifier 'my_strrchr':

#define strrchr(a, b) my_strrchr((a), (b))

It's then just for me to declare such a function - voila!

inline char *my_strrchr(const char *str, int c)
{
return(((a)+strlen((a)));
}

Luckily, my confusion about how the respective string functions should
operate has cleared. In the end I managed to sort-out the original
author's code with a single define:

#define strrchr strchr

-all happy now! Thanks.

M

Very tidy group, too. Thanks Mod.

Keith Thompson

unread,
Dec 11, 2011, 12:59:23 AM12/11/11
to
Jasen Betts <ja...@xnet.co.nz> writes:
> On 2011-12-05, Modafinil <vanl...@iinet.net.au> wrote:
[...]
>> extern _ARMABI char *strrchr(const char * /*s*/, int /*c*/)
>> __attribute__((__nonnull__(1)));
>
> looks like GCC.

No, gcc doesn't provide strrchr; it's provided by the runtime library.

On my system (Ubuntu 11.04), strrchr() is provided by the GNU C
library (glibc), which happens to come from the same oganization
as gcc. On other systems, gcc will use whatever runtime library
is provided by the OS.

The "__attribute__((...))" looks gcc-specific, but the code could
have a conditional "#define __attribute__() /* nothing */" that's
active only for non-gcc compilers. Or the code might be designed
to work only with gcc, but that doesn't imply that it's glibc.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson

unread,
Dec 11, 2011, 12:59:38 AM12/11/11
to
Barry Schwarz <schw...@dqel.com> writes:
> On Mon, 5 Dec 2011 09:15:54 -0600 (CST), Modafinil
> <vanl...@iinet.net.au> wrote:
>>Some code I'm working with uses the C string library function
>>strrchr(), but my compiler's implementation works in a non-standard
>>way. It can't seem to point to a string's first '\0' character with a
>>call like p = strrchr(dest, '\0');
>
> Since a string must contain exactly one '\0' and since that character
> will definitely be the last character in the string, your attempt to
> call strrchr with the first argument pointing to it is pointless.
>
> Further more, calling strchr or strrchr with a second argument of zero
> is a waste. The returned value is guaranteed to str+strlen(str).

I wouldn't say it's a waste; it's just a different (and perhaps more
obscure) way of doing the same thing. Any of these:

str + strlen(str)
strchr(str, '\0')
strrchr(str, '\0')

has to scan from the first character of str until it finds the
terminating '\0'; they should all have similar performance.
I'd guess that the first is likely to be the fastest, but the
difference isn't likely to be significant.

[...]

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

James Kuyper

unread,
Dec 11, 2011, 12:58:39 AM12/11/11
to
On 12/10/2011 05:07 AM, Barry Schwarz wrote:
> On Mon, 5 Dec 2011 09:15:54 -0600 (CST), Modafinil
> <vanl...@iinet.net.au> wrote:
>
>> Hi,
>>
>> Some code I'm working with uses the C string library function
>> strrchr(), but my compiler's implementation works in a non-standard
>> way. It can't seem to point to a string's first '\0' character with a
>> call like p = strrchr(dest, '\0');
>
> Since a string must contain exactly one '\0' and since that character
> will definitely be the last character in the string, your attempt to
> call strrchr with the first argument pointing to it is pointless.

It's not pointless. It's true that there's other ways of getting the
same result. For example,

for(p=dest; *p; p++);

would be my favorite. However, if done properly (and we're not sure how
he's done it, since he didn't show us the code that failed), it should
produce the result he's asking for. It wastes time doing two comparisons
at each point in the string, rather than just one, so it won't be quite
as fast, but it should work.

> Further more, calling strchr or strrchr with a second argument of zero
> is a waste. The returned value is guaranteed to str+strlen(str).
>
> You seem to be under the impression that the argument passed to
> strrchr should point to the end of the string. This is wrong.

What did he say to give you that impression?

>> In preference to altering the original code, I would like to somehow
>> re-define the function within an associated glue header file.
>> Something along the lines of:
>>
>> #define strrchr(a, b) (&a[strlen(a)])
>> or
>> #define strrchr(a, b) ((a)+strlen((a)))
>
> Before you start inventing macros, it might be a good idea to show us
> some sample code and describe what you want to accomplish.

I agree that sample code is the key thing that's missing; until we see
his code we can't be sure whether there's actually a defect in the
library implementation, or in his code (which seems far more likely).
However, his description seems clear enough to me, and a+strlen(a)
matches that description.
--
James Kuyper

Barry Schwarz

unread,
Dec 14, 2011, 1:38:48 PM12/14/11
to
On Sat, 10 Dec 2011 23:58:54 -0600 (CST), Modafinil
<vanl...@iinet.net.au> wrote:

>On Dec 10, 6:09 pm, Kenneth Brody <kenbr...@spamcop.net> wrote:

snip

>> --
>> Kenneth Brody
>> --
>> comp.lang.c.moderated - moderation address: c...@plethora.net -- you must
>> have an appropriate newsgroups line in your header for your mail to be seen,
>> or the newsgroup name in square brackets in the subject line.  Sorry.

Please don't quote signatures or other boilerplate.

>
>Thanks to everyone for the very valuable tips.
>
>Okay, I understand what my compiler was trying to tell me now, and
>have a clearer understanding of how to patch functions with glue
>definitions.
>
>#define strrchr(a, b) ((a)+strlen((a)))
>
>This didn't work because the compiler "expected an identifier". My re-
>definition '((a)+strlen((a)))
>' was unsuitable as it had no function name portion to substitute for
>the original 'strrchr' identifier.
>
>Here's a re-definition that does have a function name portion, that
>being the identifier 'my_strrchr':
>
>#define strrchr(a, b) my_strrchr((a), (b))

So a statement in your code of
strrchr(text, number);
would be translated to
my_strrchr((text), (number));

>
>It's then just for me to declare such a function - voila!
>
>inline char *my_strrchr(const char *str, int c)
>{
> return(((a)+strlen((a)));

There is no a in your function. Your function is not a macro so there
is no need to "protect" the variables by extra parentheses. return is
a statement so the outer parentheses are not needed. Did you mean
return str + strlen(str);

What is the purpose of the second parameter in your function?

>}
>
>Luckily, my confusion about how the respective string functions should
>operate has cleared. In the end I managed to sort-out the original
>author's code with a single define:
>
>#define strrchr strchr

Both this and the inline function solution above work ONLY if strrchr
is used exclusively to find the terminating '\0'. It seems to me that
disabling a standard library function which might be useful in another
section of the code falls into the category of shooting your own foot
or scoring an own goal.

If you need to find the address of the end of the string, use strlen
or strchr directly. If you do it often enough and want to use a
macro, don't give the macro the name of a standard function or a
reserved name.

--
Remove del for email

Dag-Erling Smørgrav

unread,
Dec 14, 2011, 1:38:15 PM12/14/11
to
Keith Thompson <ks...@mib.org> writes:
> No, gcc doesn't provide strrchr; it's provided by the runtime library.

Yes, gcc *does* provide its own strrchr(). It won't use it if
-fno-inline (possibly also -O0) was specified on the command line, but
you can call it explicitly as __builtin_strrchr().

See http://gcc.gnu.org/viewcvs/trunk/gcc/builtins.def?view=markup
line 556.

DES
--
Dag-Erling Smørgrav - d...@des.no

Dag-Erling Smørgrav

unread,
Dec 14, 2011, 1:38:31 PM12/14/11
to
Modafinil <vanl...@iinet.net.au> writes:
> inline char *my_strrchr(const char *str, int c)
> {
> return(((a)+strlen((a)));
> }

That won't work. It won't even compile, unless there just happens to be
a compatible definition or declaration of a in scope, or a is a
preprocessor macro that evaluates to str or some other identifier that
corresponds to a compatible definition or declaration.

Since there is one and only one '\0' in a string - the terminating NUL -
the simplest solution is to use strchr() instead of strrchr(), assuming
strchr() works properly.

DES
--
Dag-Erling Smørgrav - d...@des.no

Keith Thompson

unread,
Dec 17, 2011, 3:21:20 AM12/17/11
to
Dag-Erling Smørgrav <d...@des.no> writes:
> Keith Thompson <ks...@mib.org> writes:
>> No, gcc doesn't provide strrchr; it's provided by the runtime library.
>
> Yes, gcc *does* provide its own strrchr(). It won't use it if
> -fno-inline (possibly also -O0) was specified on the command line, but
> you can call it explicitly as __builtin_strrchr().
>
> See http://gcc.gnu.org/viewcvs/trunk/gcc/builtins.def?view=markup
> line 556.

Ok.

I just compiled a program that calls strrchr() using gcc 4.5.2 with -O3,
and the assembly listing generated an explicit call to strrchr().

But that doesn't affect the main point, that redefining predefined
functions is tricky.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Francis Glassborow

unread,
Dec 17, 2011, 11:11:49 PM12/17/11
to
On 17/12/2011 08:21, Keith Thompson wrote:
> Dag-Erling Smørgrav<d...@des.no> writes:
>> Keith Thompson<ks...@mib.org> writes:
>>> No, gcc doesn't provide strrchr; it's provided by the runtime library.
>>
>> Yes, gcc *does* provide its own strrchr(). It won't use it if
>> -fno-inline (possibly also -O0) was specified on the command line, but
>> you can call it explicitly as __builtin_strrchr().
>>
>> See http://gcc.gnu.org/viewcvs/trunk/gcc/builtins.def?view=markup
>> line 556.
>
> Ok.
>
> I just compiled a program that calls strrchr() using gcc 4.5.2 with -O3,
> and the assembly listing generated an explicit call to strrchr().
>
> But that doesn't affect the main point, that redefining predefined
> functions is tricky.
>

Not just tricky by fraught with danger. Redefining a function from the
Standard library would normally result in undefined behaviour. I know of
at least one implementation of C90 where #include a standard header
simply unlocked the already provided implementation (i.e. the header was
NOT a file)

Note also that names starting with str are among the reserved list and
so a future version of C is free to add functions starting 'str'.

Francis

ThosRTanner

unread,
Dec 21, 2011, 2:58:59 AM12/21/11
to
On Dec 11, 5:58 am, Modafinil <vanlu...@iinet.net.au> wrote:
<huge snip>
>
> #define strrchr(a, b)  ((a)+strlen((a)))
>
I suspect that is going to break at least one system header if it
appears before it

> This didn't work because the compiler "expected an identifier".

Which it looks like you did

<snip>
>
> Luckily, my confusion about how the respective string functions should
> operate has cleared. In the end I managed to sort-out the original
> author's code with a single define:
>
> #define strrchr         strchr

As these 2 functions perform completely different things, I don't
think your confusion has cleared.

>
> -all happy now! Thanks.

You might be happy. The people who're trying to maintain your code in
the future are going to be having screaming nightmares.
0 new messages