1

I am exploring some ways of making my code more user friendly.

I find it very intuitive when you have a class in Object Oriented Languages and you can easily get to all the functions that are implemented for it.

I am trying to archieve a similar effect by putting function pointers inside of my struct definitions. The only issue I have with that is having to manually pass the structure pointer every time I use it.

// What I am doing right now.
structure.do_something(&structure);
// What I would like to do. 
structure.do_something();

Is there any way of getting a pointer to that struct without passing it to the function explicitly? Also is adding function pointers to your structs a bad practice?

At first, I thought of getting to the structure by using the function pointer and moving an appropriate amount of bytes to the struct definition.

That doesn't work because the function definition is not necessarily defined in the same memory block as the structure. Even if it did work it would be a very tedious approach.

  • 4
    Why not just use C++ then? There's nothing inherently wrong in storing function pointers in structures, but if there are a lot of functions, or you have a lot of instances of the structure (or both), then you're wasting an awful lot of memory with function pointers that are basically constant and identical between instances. – pmacfarlane Jul 21 '23 at 18:16
  • 2
    You can make a macro `#define do_something(S) (S).do_something(&(S))`. – Eric Postpischil Jul 21 '23 at 18:27
  • 1
    I thought the compiler might be able to optimize it, but from [this](https://stackoverflow.com/questions/13404007/helping-the-compiler-optimize-function-pointers) question it seems like it's not able to. – Michał Gagoś Jul 21 '23 at 18:31
  • Using a macro wouldn't work well for programs with more than one data structure as some structures have similar operation names. Also, it kind of defeats the original purpose of using function pointers in your structs. Thank you for the suggestion though :) – Michał Gagoś Jul 21 '23 at 18:37
  • Did you look at the macro? It uses a function pointer. – Eric Postpischil Jul 21 '23 at 18:40
  • My bad I misunderstood what the implementation would look like. I thought that the definition of this macro would have to be defined separately for different data types. Now that I understand it it's actually a very good idea for improving readability. – Michał Gagoś Jul 21 '23 at 18:44
  • 1
    I found [Object Oriented Programming in ANSI C](https://www.cs.rit.edu/~ats/books/ooc.pdf) helpful in two ways (1) How to do it, and (2) Why not to do it that way. – David C. Rankin Jul 21 '23 at 22:09

1 Answers1

3

Is there any way of getting a pointer to that struct without passing it to the function explicitly?

No, not in any general-purpose sense.

You could write a helper macro, but that just hides the multiple appearances of the struct; it does not actually avoid them:

#define invoke(x, m) ((x).(m)(&(x)))

Also, it clobbers the syntax you were looking for.

And note, too, that that macro evaluates x twice, which could be an issue under some circumstances.

You could extend that to support "methods" that take additional arguments, though that's trickier than it may sound if you want a single macro front end for all cases.

Also is adding function pointers to your structs a bad practice?

To simulate C++ methods? That has several drawbacks relative to just using C++ in the first place, among them

  • every struct needs its own copy of all the function pointers, which makes the structs larger (possibly a lot larger) and requires you to spend extra time initializing each one.

  • your program will probably run more slowly, because the compiler cannot optimize indirect function calls as well as it can optimize direct ones (and because the structs are larger).

The whole idea seems to be merely to provide for syntax that you like better. In particular, although it may be the case that some languages that support the object.method() syntax with the semantics you are looking for provide that "you can easily get to all the functions that are implemented for [the object's type]", I don't see that being a consequence of the syntax itself.

It is not conventional to use function pointers in this way in C. Instead, it is fairly common to name the functions associated with a given data type with a distinctive prefix, and to call them directly, something like this:

struct mytype instance;

// ...
result = mytype_do_something(&instance);
John Bollinger
  • 160,171
  • 8
  • 81
  • 157