-4

I wanted to make an object oriented preprocessor to my programming language which converts my language into C (like early C++). And I want to simulate the classes with structures. And the question is: how can I declare a variable inside a struct like this:

typedef struct { //equivalent of class
   int a = 5;
   int (*sub)(int) = &int_sub; //function of a class, uses an external declared function
} class_name;

I tried the code above but the compiler wrote this:

error: expected ‘:’, ‘,’, ‘;’, ‘}’ or ‘__attribute__’ before ‘=’ token 
       void (*sub)(int) = &int_sub;

I have two questions:

  1. Can I declare a variable inside a struct?

  2. If yes, how?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
wyncze13
  • 11
  • 1
  • 3
  • 2
    You are inventing your own programming language but don't know how to declare a struct? Hmm... :) – Lundin Feb 01 '16 at 09:55
  • Anyway first question you should ask here: how does it make sense for your class to use an externally defined function internally? Is this some sort of functor? – Lundin Feb 01 '16 at 10:05

3 Answers3

8

You can't assign a pointer value inside a struct definition. You could use a function to init it.

typedef struct { //equivalent of class
   int a;
   int (*sub)(int);
} class_name;

int int_sub (int a)
{
   // your stuff
   return 0;
}

int main()
{
   class_name myClassVariable;

   myClassVariable.a = 5;
   myClassVariable.sub = int_sub;

   printf("class_name.a = %d\n", myClassVariable.a );
   printf("class_name.sub = %p\n", myClassVariable.sub );
   printf("int_sub address = %p\n", int_sub );

   return 0;
}

Or, as shown in artm answer, you could init your allocated variable:

class_name my_struct = { .a = 5, .sub = int_sub };
LPs
  • 16,045
  • 8
  • 30
  • 61
  • That's not true. You can also use a simple initializer to initialize the structure. No function needed. – fuz Feb 01 '16 at 09:55
  • @FUZxxl You right. I'm going to edit. – LPs Feb 01 '16 at 09:56
  • Preferably you should implement classes with _opaque type_ so how you initialize the struct in main isn't really relevant because you shouldn't do that in the first place - it is bad OOP. Instead it should be initialized from inside the constructor for the opaque type. For example `class_name* class_init (int a) { class_name* new_class = malloc(sizeof(*new_class)); new_class->a = a; new_class->sub = you_probably_want_a_static_function_here; return new_class; }` – Lundin Feb 01 '16 at 10:00
  • @Lundin Good answer +1. As well what I usually do. I Thought OP level was a little low to move discussion to pointers and opaque types. – LPs Feb 01 '16 at 10:23
  • @Lundin I wonder, how many OOP zealots would consider initialisation to include allocation; this is also *bad OOP* (actually, it's technically non-compliant OOP). I tend to prefer something more `memcpy`-inspired, such as `T *T_init(T *destination, T source) { return destination ? memcpy(destination, &source, sizeof source) : NULL; }` as this allows the caller to choose what form of allocation is most appropriate :) – autistic Feb 12 '17 at 02:59
  • @Seb There's no reason why it would be bad OOP. If you are concerned about the allocation method, you can simply put that in a separate function `alloc()`, which in turn either calls malloc, alloca or your own memory pool. The alternative in C is to not have private encapsulation, which your memcpy() version lacks completely. If the allocation is done by the caller, then they also have full access to all member variables. – Lundin Feb 13 '17 at 07:13
  • @Seb Instead you could do `class_name* class_init (alloc_t* alloc, int a) { class_name* new_class = alloc(sizeof(*new_class)); ...` where `alloc_t*` is a function pointer. – Lundin Feb 13 '17 at 07:14
  • @Lundin It is a violation of [DIP](https://en.wikipedia.org/wiki/Dependency_inversion_principle), which makes it bad OOP. Additionally, consider how C is designed; does `scanf` allocate memory for you, or does it allow you the grace to choose how you allocate memory yourself? A higher-level function won't do; that excludes automatic storage duration, which is an immensely useful tool for prototyping, among other purposes! – autistic Feb 14 '17 at 02:57
  • @Seb So you think it is better OOP to not have any private encapsulation at all, just tossing around global structs? Might as well put all your variables in as externs in a "global_goo.h"... then the caller can chose how to allocate them. – Lundin Feb 14 '17 at 07:25
  • @Lundin Encapsulation isn't a violation of DIP; higher-level modules (e.g. your `class_name`, and the functions that operate upon it) depending upon lower-level modules (e.g. `malloc`) is. Abstracting this away using a function pointer argument isn't much better, as your abstraction *still* depends upon details that might not be the most appropriate for all usecases (i.e. the storage durations you permit might be excessive, and as a result cause projects using it to become excessively complex). – autistic Feb 15 '17 at 02:34
  • @Lundin Does `strcat` allocate memory for you, or accept a function pointer that allocates memory for it? If you deviate from the standard pattern, users of your code will need to be trained to use your pattern. That's wasteful, especially considering that your pattern is restrictive when compared to the standard pattern. – autistic Feb 15 '17 at 02:36
  • @Seb To begin with, everyone knows that the C standard lib is a collection or more or less awfully written functions, from a time long before good programming practice was even invented. The standard lib API is inconsistent, unintuitive and often plain horrible. That being said, the reason `strcat` doesn't allocate memory for me is because it is not part of an ADT. It is better to ask: "does std::string allocate memory for you? std::vector? std::map?" Yeah, they all do. And no, you can't pick the allocation method for them, making them completely useless in embedded systems. – Lundin Feb 15 '17 at 07:45
  • @Lundin As a matter of fact, `std::string`, `std::vector` and `std::map` all permit custom allocators which excludes no form of storage duration, making them useable for embedded systems; they don't violate DIP. Your *least non-compliant* (though still slightly non-compliant) suggestion excludes automatic storage duration; this is in violation of DIP. – autistic Feb 16 '17 at 02:32
4

Alternatively, you can also initialize the variable of your struct type.

int func( int a ){}

typedef struct {
    int a;
    int (*sub)(int);
} class_name;

class_name my_struct = { .a = 5, .sub = func };
artm
  • 17,291
  • 6
  • 38
  • 54
1

I take it your question is not about how to declare but how to initialize a structure member.

Define the class as opaque type in the h file. Use typedef for function pointers.

h file

// opaque type declaration
typedef struct class_name class_name;

// types used by this class
typedef int sub_func_t (int);

// member functions of the class
class_name* class_init (int a, sub_func_t* sub);

Then initialize it from inside its constructor:

c file

struct class_name { //equivalent of class
   int a;
   sub_func_t* sub;
};

class_name* class_init (int a, sub_func_t* sub) 
{ 
  class_name* new_class = malloc(sizeof(*new_class)); 
  assert(new_class != NULL);
  *new_class = (class_name){a, sub};
  return new_class; 
}
Lundin
  • 195,001
  • 40
  • 254
  • 396