3

As another Javascript developer learning C, I'm trying to implement a basic object.

UserStruct.h

#ifndef USERSTRUCT_H
#define USERSTRUCT_H

struct User {
    int age;
    int (* getAge)();
};
typedef struct User User;

int getAge(User);
User initUser(int);
#endif /* USERSTRUCT_H */

UserStruct.c

#include "./UserStruct.h"
int getAge(User this) {
  return this.age;
} 

User initUser(int age){  
  User user;
  user.age = age;
  user.getAge = getAge;
  return user;
}

main.c

#include <stdio.h>
#include <stdlib.h>
#include "./UserStruct.h"
int main(int argc, char** argv) {
   User user = initUser(15); // sets age to 15..
   user.age = 2222;
   printf("%d\n",user.getAge(1234)); // note the int passing here..
   printf("%d\n",user.age);
  return (EXIT_SUCCESS);
}

Questions!:
1. Can someone explain the syntax int (* getAge)(); inside the UserStruct definition?
2. getAge expects a User to be passed to it, how come it works with an int being passed in? This is especially strange as the implementation of getAge uses return this.age.

While I did figure out how to fix it, I'm still not sure why this behaves the way it does. (The solution is to pass a pointer of the User into getAge)

10
  • 5
    Your program doesn't work. It exhibits undefined behavior which makes your whole program ill-formed and invalid. The UB stems from your call passing an invalid argument to the getAge function. Commented Jul 28, 2017 at 8:57
  • 3
    not again. Please stop trying to force C to work as another language/paradigm you are accustomed to. You can't do OOP in C. You can't do overloading in C. You can't do polymorphism in C. you can't have member functions in C. Please stop trying to do so. Use C as C or use another language where you can use the paradigm you want. Commented Jul 28, 2017 at 8:58
  • 4
    I'm still not sure why this behaves the way it does. Undefined behavior is undefined. The solution is to pass a pointer of the User into getAge Not per the posted code it's not. The solution is to pass a struct User to getAge(), not a pointer of any kind, and also to declare int (* getAge)(); as int (* getAge)( struct User); instead. Commented Jul 28, 2017 at 8:58
  • 3
    As for the declaration int (* getAge)(), that declares getAge to be a pointer to a function taking an indeterminate number of arguments of indeterminate type, returning an int. Commented Jul 28, 2017 at 8:58
  • 1
    This'll be a duplicate of Can you write object-oriented code in C? or one of the many other threads about OOP in C, e.g. stackoverflow.com/questions/524033/… Commented Jul 28, 2017 at 9:06

2 Answers 2

3

C is not an object oriented language as it existed before object, but your example is demonstrating that it can be used with objects.

  • int (* getAge)() is a function pointer, the function takes any parameters () and returns int, to specify that the function takes no parameter should be defined (void)

  • getAge is a "method" of class user it needs an object instance, in object languages the syntax would be user.getAge() which passes implicitly this as first argument, in C it's explicit: getAge(user).

The problem is that an int can be used as pointer which means user.getAge(1234) will use 1234 as an address to a user so will take the second int field as an address to fuction getAge and jump to this address.

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks, so apart from code being wrong(which I already wrote that I knew it was), I'm getting these behaviors because they're undefined, which means anything can happen. apart from that, assuming I pass correct "instances" to the "member functions" it should operate as expected.
@M.M, it will be used as pointer because user.getAge points to getAge function defined in UserStruct.c. the declaration int(*getAge)() allows to use any arguments, int(*getAge)(void) will prevent this.getAge=getAge;
getAge is a function pointer, 1234 is a function argument. The function being pointed to doesn't even take any pointer arguments.
getAge is a function pointer that can take any argument because of (). 1234 is an argument and the real function getAge expects a User argument so dereferencing 1234 may raise a Segmentation fault
This makes no sense. When is the argument this dereferenced? this is not even a pointer. This is undefined behavior that can be resolved by changing the declaration of the function pointer to: int (* getAge)(struct User); so that an incompatible-type error is raised at compilation with: user.getAge(1234). Even better to remove the superfluous typedef.
|
2

I've modified your code in a way that it runs better.

The getAge field of the structure User is a pointer to a function. I've modified its prototype to obtain it points a function that receives a pointer to the structure from which you want get the age field contents. (I used a pointer to the structure to avoid to transfer the entire structure by means the stack)

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdlib.h>

struct User {
    int age;
    int (* getAge)(struct User *);
};

typedef struct User User;

int getAge(User *);
User initUser(int);

int getAge(User * this_) {
  return this_->age;
}

User initUser(int age){
  User user;
  user.age = age;
  user.getAge = getAge;
  return user;
}

int main(int argc, char** argv) {
   User user = initUser(15); // sets age to 15..

   // user.age = 2222;

   printf("%d\n",user.getAge(&user)); // note the pointer used as parameter

   printf("%d\n",user.age);
  return (EXIT_SUCCESS);
}

5 Comments

Thanks, is there a way to abstract the passage of instance(or pointer) to the function? I already heard that overloading is not a possibility
This is not C++ is C. If you look at the code I've sent you, you note that I've renamed the variable this as this_, thus avoid confusion between C and C++.
Overloading is not a capability of the C language.
The more I learn about C the more I admire people who are working on it day to day! It's like programming with handcuffs :) Thanks for all your help!
If you want things that were pretty much the first things C++ added to C, use C++, not C.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.