Search code examples
cobjectoop

Incompatible pointer types error only on my local machine and not on online IDE


I was brushing up on my Design Patterns in C here, and while trying to run this object method design example they have on their site:

#include <stdio.h>

// Define a structure to represent an object
typedef struct {
    // Data members
    int value;

    // Function pointer for a method
    void (*print)(const struct MyObject *);
} MyObject;

// Method to print the value of the object
void printValue(const MyObject *obj) {
    printf("Object value: %d\n", obj->value);
}

// Function to initialize an object
void initializeObject(MyObject *obj, int initialValue) {
    obj->value = initialValue;
    obj->print = &printValue; // Assign the function pointer
}

int main() {
    // Create an instance of MyObject
    MyObject myObj;

    // Initialize the object
    initializeObject(&myObj, 42);

    // Use the object's method
    myObj.print(&myObj);

    return 0;
}

I get these errors:

main.c:9:30: warning: declaration of 'struct MyObject' will not be visible outside of this function [-Wvisibility]
  void (*print)(const struct MyObject *);
                             ^
main.c:20:14: error: incompatible function pointer types assigning to 'void (*)(const struct MyObject *)' from 'void (*)(const MyObject *)' [-Wincompatible-function-pointer-types]
  obj->print = &printValue; // Assign the function pointer
             ^ ~~~~~~~~~~~
main.c:31:15: warning: incompatible pointer types passing 'MyObject *' to parameter of type 'const struct MyObject *' [-Wincompatible-pointer-types]
  myObj.print(&myObj);
              ^~~~~~
2 warnings and 1 error generated.

This makes sense to me since the MyObject struct doesn't have the necessary visibility. It works just fine when I change it to:

typedef struct MyObject {
  // Data members
  int value;

  // Function pointer for a method
  void (*print)(const struct MyObject *);
} MyObject;

I'm just wondering why it compiles on all the online IDE's

Edit:

It gets compiled in the example provided in the link:

geeksforgeeks

As well as these: tutorialspoint

codechef

Those were the first 3 that I tried, but i do see some now throwing the same errors


Solution

  • "why it compiles on all the online IDE's" is clearly false. You have not tried all of them and @3CxEZiVlQ provided you with a counter example. You show one error, assignment of incompatible types, and two warnings in the above. The error message is pretty clear that obj->print and &printValue are totally unrelated pointer types. This may work, and indeed does, this case, but those online IDEs should generate an error.

    You can get this to compile without any errors and warnings with a forward declaration and a couple of casts. This is because dereference happens of the declared type and struct MyObject * is a pass-through.

    #include <stdio.h>
    
    struct MyObject;
    
    typedef struct {
        int value;
        void (*print)(const struct MyObject *);
    } MyObject;
    
    void printValue(const MyObject *obj) {
        printf("Object value: %d\n", obj->value);
    }
    
    void initializeObject(MyObject *obj, int initialValue) {
        obj->value = initialValue;
        obj->print = (void (*)(const struct MyObject *)) &printValue;
    }
    
    int main() {
        MyObject myObj;
        initializeObject(&myObj, 42);
        myObj.print((struct MyObject *) &myObj);
    }
    

    It would be more clear to use a const void * instead of const MyObject void * and now you only need to cast before dereferencing:

    #include <stdio.h>
    
    typedef struct {
        int value;
        void (*print)(const void *);
    } MyObject;
    
    void printValue(const void *obj) {
        printf("Object value: %d\n", ((MyObject *) obj)->value);
    }
    
    void initializeObject(MyObject *obj, int initialValue) {
        obj->value = initialValue;
        obj->print = &printValue;
    }
    
    int main() {
        MyObject myObj;
        initializeObject(&myObj, 42);
        myObj.print(&myObj);
    }
    

    The better option, of course, is to declare struct MyObject as you pointed out.