Thread: strchr question

  1. #1
    Registered User
    Join Date
    Feb 2015
    Posts
    2

    strchr question

    Can someone explain what this snippet of C is doing, especially strchr? Is it testing to see if the pointer in cmp is equal to the pointer to strchr function or is it testing if something completely different is equal?

    Code:
    void *cmp;
    if (cmp == (void *)strchr) { Then do this; }
    Thanks.

  2. #2
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Right now the snippet isn't doing anything useful. Since you want to use void * in the snippet, that means basically, you are comparing one memory address to another address. It ignores all of the interesting things about function pointers. You can't call strchr with cmp, for instance. Void pointers cannot be dereferenced.

    An unadorned function name, like "strchr", which is a literal function pointer, can be compared with void pointers incidentally, and other function pointers of the same type. By type, I mean the kind of function the pointer is - they can be different in terms of parameter count, order, and type, and in terms return type. If you have a bunch of similar functions, a comparison would let you discern what the pointer will do when it is invoked by the call operator (). I don't find that very useful, . I mean, you would call strchr - or any similar function - by storing the address in the pointer and then dereferencing (calling) on the pointer. If you aren't sure what the function pointer could point to, then code that uses function pointers is not going to be the cleanest solution to the problem anyway.

    In this situation the comparison would be true, at least:
    Code:
    void *cmp = &strchr;
    if (cmp == (void *)strchr) { ... }
    You can't necessarily depend on strchr having a hardcoded address.

  3. #3
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    Quote Originally Posted by storax70681 View Post
    Code:
    (void *)strchr
    should be
    Code:
    (void *)&strchr

  4. #4
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by Yarin View Post
    should be
    Code:
    (void *)&strchr
    Nope.

    If you go by C89 or C99 rules (I haven't checked C11), you cannot cast function pointers to object pointers or vice versa. Furthermore, strchr and &strchr are the exact same thing; function pointers are funky in C.

    In other words, ISO C forbids
    Code:
    void *p;
    p = strcmp;
    p = &strcmp;
    but only because it does not allow you to assign a function pointer to an object pointer. The workaround is simple:
    Code:
    void *p;
    *(int (**)(const char *, const char *))&p = strcmp;
    Note that above, int is the function result type, and the const char *, const char * are the parameters the function takes. The ** means we have a pointer to a pointer to such a function. In other words, we take the address of the variable, cast it to an address to a function pointer, and then dereference and assign.

    When using a function such as dlsym() which returns a pointer to a function as a void pointer, you need to use
    Code:
    int (*func)(const char *, const char *);
    *(void **)&func = dlsym(NULL, "strcmp");
    which is basically the reverse. We take the address of a function pointer variable, cast that to a pointer to a void pointer, dereference, and assign.

    To correctly print the address of a function, you need to use a temporary void pointer. For example,
    Code:
    *(int (**)(const char *, const char *))&p = strcmp;
    printf("The address of strcmp is %p\n", p);
    
    *(int (**)(const char *, const char *))&p = &strcmp;
    printf("The address of strcmp is %p\n", p);
    Both do the same thing. I prefer the first one, because it keeps the funkyness of the function pointers fresh in my mind; I've found it works for me best.

    The reason for this mess is that there are architectures where function pointers are not standard pointers, and may require special handling from the compiler. The above workaround patterns were actually suggested by the C standard developers, so if you happen to run code on such a rare architecture, the above code should work there just fine, whereas the typical "I don't care about those stupid warnings, this works on my machine" code tends to fail in spectacular ways.

  5. #5
    Registered User
    Join Date
    Feb 2015
    Posts
    2
    Thanks for the interesting discussion. I have posted a little more of the original code. I have to port this code from a C compiler on Unix into visual studio's C++ compiler and it gets confused because strchr is overloaded. Could the original intent simply have been a value/no value type of test?

    Here's the rest of the function:
    Code:
    void markerToString(void *cmp, char *marker, char *mrkString)
    {
        if (cmp == (void *)strchr)
        {
            char c = *marker;
            sprintf(mrkString, "%c", c);
        }
        else
            strcpy(mrkString, marker);
    }

    Thanks

  6. #6
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by storax70681 View Post
    Code:
    void markerToString(void *cmp, char *marker, char *mrkString)
    All I can think of, is that cmp is actually a function pointer, namely the function used to look for marker. (In that case, if compiled with warnings enabled, this project spews a ton of warnings.)

    The logic is then that if marker was found using strchr function, then marker has to be a pointer to a single character (as that's how strchr() works), and marker and a string-terminating nul byte is saved to mrkString (to make it match the marker but as a string). Otherwise, marker is considered a string, and copied to mrkString.

    Ew.

    The only reason for such an interface is when this function is used in a function where the original caller defines the callback function used for locating the marker -- i.e. somewhat similar to the qsort() C library function.

    Unfortunately, the programmer is wrong. The programmer obviously assumed that ONLY if strchr() was used as the locator function (see qsort() for an interface that takes a comparison function), is marker a pointer to a single character, and not a string. Unfortunately, strrchr() and any user function with a matching prototype do so too. So, if you supplied say strrchr() to the original function that calls this function, this function would work wrong.

    I recommend you do a bit of creative surgery, and change the interface for the function that calls this function. In addition to whatever defines marker, you need to know the number of characters in marker. Note that marker might still not be a string; there might not be a terminating nul byte '\0' at the end.

    Then, you can trivially replace this function with
    Code:
    void markerToString(char *mrkString, const char *marker, const size_t markerlen)
    {
        if (markerlen > 0)
            memmove(mrkString, marker, markerlen);
        mrkString[markerlen] = '\0';
    }
    Of course, dispensing with the function pointer altogether and making sure marker is always a string, would be much saner in the long run.
    Last edited by Nominal Animal; 02-01-2015 at 10:17 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Please help me using strchr
    By lovy poe in forum C++ Programming
    Replies: 8
    Last Post: 08-22-2011, 05:29 PM
  2. Question: The strchr function
    By everyone0 in forum C Programming
    Replies: 12
    Last Post: 11-16-2010, 02:35 PM
  3. using strchr
    By breaka in forum C Programming
    Replies: 3
    Last Post: 08-12-2006, 12:33 PM
  4. strchr()
    By paperbox005 in forum C Programming
    Replies: 8
    Last Post: 08-08-2004, 02:29 AM
  5. strchr
    By client in forum C Programming
    Replies: 2
    Last Post: 05-12-2002, 12:41 PM