C: "Calculated member" in struct

Discussion in 'Mac Programming' started by Nermal, Aug 29, 2015.

  1. Nermal, Aug 29, 2015
    Last edited: Aug 29, 2015

    Nermal Moderator

    Nermal

    Staff Member

    Joined:
    Dec 7, 2002
    Location:
    New Zealand
    #1
    Hi everyone,

    I'm trying to learn plain old C; I'm reasonably proficient with C# but new to C. I'm trying to figure out whether there is a way to do a "calculated member" (for want of a better name) in a struct. For example, starting with the following:

    Code:
    typedef struct {
        int Width;
        int Height;
    } Rectangle;
    
    I'd like to be able to add some sort of "int Area = Width * Height;". It'll obviously be more complicated than that, but is this sort of thing possible in C? I've created a function called Rectangle_Area that takes a Rectangle and returns an int, but I'm not sure whether there's a way to "link" it into the main struct. I don't yet know all the terms that I should be searching for so can someone please help a newbie out? :)
     
  2. subsonix, Aug 29, 2015
    Last edited: Aug 29, 2015

    subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #2
    Do you mean that you would like to add a function to the struct? You can do that with a function pointer, but it's a bit convoluted since you can not refer to the struct itself from within the struct. This is a benefit of OOP languages like C++ or Obj-C they both have a "this" pointer which does that. In the case of C, you'd need to add the struct itself as an argument to the function.

    Edit: an example

    Code:
    #include <stdio.h>
    
    typedef struct rectangle{
      int width;
      int height;
      int (*area)(struct rectangle *rect);
    } rectangle;
    
    int area(rectangle *rect) {
      return rect->width * rect->height;
    }
    
    int main(void)
    {
      rectangle rect = {2, 3, area};
    
      printf("Area: %d\n", rect.area(&rect));
    
      return 0;
    }
    
    I need to type out the struct name in the struct declaration or use a void pointer or the area function declaration don't know what a rectangle is since that appear the row just below.
     
  3. Nermal thread starter Moderator

    Nermal

    Staff Member

    Joined:
    Dec 7, 2002
    Location:
    New Zealand
    #3
    Aha! That does indeed work so thanks for that. I've also learned the magic words "function pointer" to put into Google :)
     
  4. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #4
    They can be quite useful if you are trying to make a generic function that need to work on many data types. An example can be found in the stdlib's qsort() function. Since this sorting function should be able to sort anything, from numbers, strings, to rectangles, you need to add a compare function that knows what it means to be less, greater or equal to something. From the function declaration in the man page:

    Code:
    qsort(void *base, size_t nel, size_t width, int (*compar)(const void *, const void *));
    
    It's the last parameter here, and it also takes two arguments, both void pointers since the function needs to be able to sort anything. Sometimes in libraries like CoreFoundation or CoreAudio for example, you'll see the arguments as a separate "context" parameter, which is even more generic, you are then able to add any amount of argument to your supplied function in the context as a struct.
     
  5. mrichmon macrumors 6502a

    Joined:
    Jun 17, 2003
    #5
    With the code example from subsonix above you can also simplify the invocation by defining a macro:

    Code:
    /* Invoke method Y on struct X.*/
    #define invoke(X, Y) X.Y(&X)
    
    So the printf then can become:
    Code:
    printf("Area: %d\n", invoke(rect, area));
    
    This is effectively the beginning of implementing object-oriented programming model. If this is your goal, it is worth looking at ooc and GObject as related efforts.
     
  6. Nermal thread starter Moderator

    Nermal

    Staff Member

    Joined:
    Dec 7, 2002
    Location:
    New Zealand
    #6
    Using a #define looks like an interesting idea, but give me too many ideas and I'll end up using C# syntax in my C code :)
     

Share This Page