Sunday, April 17, 2011

Rewriting C++ methods in C

How can I make equivalents to these methods in C? I read somewhere that they could be "replaced with functions that take a structure pointer as the first parameter," but I'm not sure how to do this, if that is the right thing to do.

struct SCustomKeys
{
    struct SCustomKey Save[10];
    struct SCustomKey Load[10];
    struct SCustomKey Slot[10];

    struct SCustomKey PrintScreen;
    struct SCustomKey LastItem; // dummy, must be last

    //--methods--
    struct SCustomKey &key(int i) { return ((SCustomKey*)this)[i]; }
    struct SCustomKey const &key(int i) const { return ((SCustomKey*)this)[i]; }
};

Here's an example of how they are used:

void ZeroCustomKeys (SCustomKeys *keys)
{
    int i = 0;

    SetLastCustomKey(&keys->LastItem);
    while (!IsLastCustomKey(&keys->key(i))) {
     keys->key(i).key = 0;
     keys->key(i).modifiers = 0;
     i++;
    };
}

More context: http://pastebin.com/m649210e8

Thanks for the help. I haven't been able to the suggested replacement for the C++ method working with this function yet though. Any ideas on how to approach this?

void InitCustomKeys (struct SCustomKeys *keys)
{
    UINT i = 0;

    SetLastCustomKey(&keys->LastItem);
    while (!IsLastCustomKey(&keys->key(i))) {
     SCustomKey &key = keys->key(i);
     key.key = 0;
     key.modifiers = 0;
     key.handleKeyDown = NULL;
     key.handleKeyUp = NULL;
     key.page = NUM_HOTKEY_PAGE;
     key.param = 0;
     i++;
    };

    //an example key
    keys->PrintScreen.handleKeyDown = HK_PrintScreen;
    keys->PrintScreen.code = "PrintScreen";
    keys->PrintScreen.name = L"Print Screen";
    keys->PrintScreen.page = HOTKEY_PAGE_MAIN;
    keys->PrintScreen.key = VK_PAUSE;
}

And the new function I'm trying now is:

 struct SCustomKey* key(struct SCustomKeys *scs, int i) { 
    return &(((SCustomKey*)scs)[i]); 
 }
From stackoverflow
  •  struct SCustomKey &key(int i) { return ((SCustomKey*)this)[i]; }
     struct SCustomKey const &key(int i) const {
         return ((SCustomKey*)this)[i]; 
     }
    

    will become

     struct SCustomKey* key(struct SCustomKeys *scs, int i) { 
        /* Shouldn't you be using one of Load/Save/... arrays? */
        return &(((SCustomKey*)scs)[i]); 
     }
    

    C does not have const functions. So, only one version.

    Reed Copsey : If you look at his code, he's editing the return value (since he's returning a reference to a SCustomKey). Wouldn't he need a pointer returned in order to handle that correctly in C?
    Greg Rogers : You would probably name it something more descriptive than "key" to avoid name conflicts. And you'd return by pointer since the original returned by reference. And if you wanted to make a const version you'd jast name it "*_const".
    dirkgently : @Greg: You don't gain much with such a construct in C.
    dirkgently : @Reed Copsey: Probably. I'll update.
  • The idea is that you would pass in a pointer to an SCustomKeys as the first (well, it doesn't really matter; it could be any) parameter, and use it in place of "this".

  • Basically, instead of having a member function like:

    struct SCustomKey &key(int i) { return ((SCustomKey*)this)[i]; }
    

    You will need to rewrite this as a function that takes a pointer to a SCustomKeys as it's first argument.

    The function will look like:

    SCustomKey* key(SCustomKeys* customKeys, int i) 
    { return ((SCustomKey*)(customKeys)+i); }
    

    This should provide you with a pointer to the element you are trying to access.

    dirkgently : Mention that this usage of SCustomKey will require a typedef.
    Reed Copsey : Good point - I almost always typedef my structs, so I forgot to mention that.
  • I'll explain using your example. This is your code (actually only the methods):

    struct SCustomKeys
    {
        // snipped
    
        //--methods--
        struct SCustomKey &key(int i) { return ((SCustomKey*)this)[i]; }
        struct SCustomKey const &key(int i) const { return ((SCustomKey*)this)[i]; }
    };
    

    And this is how I'd write it in C:

    1. add a pointer to the struct the method should act upon.
    2. return pointers instead of references, since C doesn't have references.
    3. I don't think const can be used the same in C, so we only need one version.
    struct SCustomKeys
    {
        // snipped
    };
    //--methods-- (outside the struct)
    
    struct SCustomKey *key(struct sCustomkey *this, int i) { return &(((SCustomKey*)this)[i]); }
    
    jmucchiello : You can fake the const version by returning copied structs instead of pointers: struct SCustomKey key_const(struct SCustomKey* this, int i) { return ((SCustomKey*)this)[i]; }

0 comments:

Post a Comment