Keil compiler v5 to v.6

165 Views Asked by At

I'm forced to switch from ARMCC v5 to CLANG(v.6). Here is the problem. I have some struct that includes a pointer to the function which gets as a parameter pointer to the same structure. So I do

struct _some_struct_s;
typedef void (*callback_f)(struct _some_struct *p);
 
typedef struct {
  callback_f fn;
  int        x; 
} some_type_s;

// init function
void init_some_struct (some_struct *p, callback_f f) {
  p->fn = f;
  p->x = 0;
}

In another file I'm writing the callback() and calling init_some_struct()

some_type_s  my_struc;
void callback (some_type_s *p) {
  p->x++;
}
init_some_struct (&my_struc, callback);

I had no issues with compiler 5 but a warning with version 6.


warning: incompatible function pointer types passing 'void (some_struct_s *)' to parameter of type 'callback_f' (aka 'void (*)(struct _some_struct_s *)') [-Wincompatible-function-pointer-types]

What can I do to avoid having this warning?

What can I do to avoid having this warning?

4

There are 4 best solutions below

0
Submin On BEST ANSWER

@ John Bollinger Thank you. I resolved my issue.

typedef struct _some_struct_s {
...
}some_struct_s;

Sorry for the inconvenience.

5
gulpr On
  1. typedef (*callback_f)(struct _some_struct *p); - you alias the type as function of pointer which returns int.

It should be typedef void (*callback_f)(struct some_struct *p);

  1. typedef struct {
         callback_f *fn;
    
    fn is a pointer to pointer to function. It should be callback_f fn;
typedef struct some_struct _some_struct_s;
typedef void callback_f(struct _some_struct *p);
 
typedef struct some_struct{
  callback_f *fn;
  int        x; 
} some_struct_s;

// init function
void init_some_struct (some_struct *p, callback_f *f) {
  p->fn = f;
  p->x = 0;
}
6
dbush On

The parameter to a function pointer of type callback_f has type struct _some_struct *, while the function callback takes an argument of type some_type_s * where some_type_s is an alias for an anonymous struct type. These are not the same.

Presumably these should be the same, so you need to give that anonymous struct a tag:

typedef struct _some_struct {
  callback_f *fn;
  int        x; 
} some_type_s;
6
John Bollinger On

The code presented is not internally consistent. I'm having trouble believing that any compiler accepted it, but I'm uncertain whether that's because you've omitted other relevant pieces or because even with your corrections it still doesn't match the code that your old compiler accepted.

This is what I think you're looking for, annotated in code comments:

// Forward declaration of type struct some_struct_s
// This is needed because this type is self referential via
// the type of the callback function.
struct some_struct_s;

// "callback_f" declared as an alias for type void (*)(struct some_struct_s *p)
typedef void (*callback_f)(struct some_struct_s *p);
 
// Definition of type struct some_struct_s
// I have removed the typedef part because the name of the typedef alias was confusing
// (probably wrong), and because it is unneeded.
struct some_struct_s {
    callback_f fn;
    int        x; 
};

// But if you really want the typedef, then you can declare it separately:
typedef struct some_struct_s some_struct;

// This is how to declare the function without relying on alias "some_struct"
void init_some_struct (struct some_struct_s *p, callback_f f) {
    p->fn = f;
    p->x = 0;
}
// ...

// C does not support nested functions, so this should be at file scope, outside
// any function
void callback(struct some_struct_s *p) {
    p->x++;
}

// ...
// But function _calls_ must appear only inside function bodies, so for example:
void some_other_function(void) {
    // ...
    struct some_struct_s my_struc;
    init_some_struct(&my_struc, callback);
    // ...
}

Addendum: the same thing, a different style

Since you seem highly motivated to use a different style, and do not recognize how to convert the above, here is a version that focuses using a typedef alias for your structure type:

// Forward declaration of type struct some_struct_s
// This is needed because this type is self referential via
// the type of the callback function.
// The name of the type being declared is "struct some_struct_s", and the tag is
// essential for what you're trying to do.
struct some_struct_s;

// This typedef could be combined  with the previous declaration, if you prefer.
// Separating it emphasizes the separate significance of the typedef
// and forward declaration.
// Declaring it here allows it to be used in all the subsequent declarations.
typedef struct some_struct_s some_struct;

// "callback_f" declared as an alias for type "void (*)(some_struct *p)"
typedef void (*callback_f)(some_struct *p);
 
// Definition of type struct some_struct_s
// The tag is essential here.  It's what allows other declarations
// to refer to this structure type.
struct some_struct_s {
    callback_f fn;
    int        x; 
};

void init_some_struct (some_struct *p, callback_f f) {
    p->fn = f;
    p->x = 0;
}
// ...

// C does not support nested functions, so this should be at file scope, outside
// any function
void callback(some_struct *p) {
    p->x++;
}

// ...
// But function _calls_ must appear only inside function bodies, so for example:
void some_other_function(void) {
    // ...
    some_struct my_struc;
    init_some_struct(&my_struc, callback);
    // ...
}

Essentials:

  • the name of the structure type involved there is struct some_sruct_s, formed from the struct keyword and the structure tag. In C, the tag is not a name for the type by itself, but that's different in C++.
  • You can choose whatever tag you like for the structure type, including the typedef name, but you cannot omit the tag altogether. That's what allows the type to be referenced before its declaration is complete, including inside its own declaration. Every variation on self reference requires that.
  • the typedef declaration declares some_struct as an alias for type struct some_struct_s. Anywhere the typedef is in scope, the two names for the type can be used interchangeably. (The typedef's scope is necessarily a subset of the structure type's scope).