2

I am trying to use a function pointer inside a struct, whereas the function pointer needs an instance of the struct itself as argument. My current code snippet looks like this:

#include "stdio.h"
#include "stdint.h"

typedef struct MYSTRUCT_S MYSTRUCT;

typedef struct {
  int (*isInRange)(const MYSTRUCT* pDataPoint, const uint16_t newValue);
  const uint16_t minValue;
  const uint16_t maxValue;
} MYSTRUCT_S;

int isInRange(const MYSTRUCT* pDataPoint, const uint16_t newValue) {
  MYSTRUCT* mDatapoint = (MYSTRUCT*)pDataPoint;
  if ((newValue < mDatapoint->minValue) || (newValue > mDatapoint->maxValue)) {
    return 0;
  } else {
    return 1;
  }
}

int main() {
static MYSTRUCT* maDataPoint = NULL;
maDataPoint->isInRange(maDataPoint, 6);
return 0;
}

The compiler complains about: error: invalid use of incomplete typedef 'MYSTRUCT' {aka 'struct MYSTRUCT_S'}"

I was already reading through the following items, but could not find the solution for my issue:

Any idea, how I could solve this issue?

10
  • 2
    What's the point of MYSTRUCT* mDatapoint = (MYSTRUCT*)pDataPoint;? Just use pDataPoint in the rest of the function. Commented Sep 30, 2024 at 18:45
  • 5
    You never define struct MYSTRUCT_S anywhere. You define MYSTRUCT_S as a typedef to an anonymous struct. Commented Sep 30, 2024 at 18:47
  • 4
    Change typedef struct { to typedef struct MYSTRUCT_S { Commented Sep 30, 2024 at 18:48
  • 2
    Unrelated: maybe consider rewriting your code in C++ and compile with a C++ compiler :-) Commented Sep 30, 2024 at 18:48
  • 1
    Aside, instead of #include "stdio.h" use #include <stdio.h> etc., unless you plan to supply your own versions locally. Commented Sep 30, 2024 at 18:54

4 Answers 4

3

You defined a type named MYSTRUCT_S but you did not define a type named struct MYSTRUCT_S.

typedef struct { ... } MYSTRUCT_S;

should be

struct MYSTRUCT_S { ... };

The next problem is the NULL dereference in main.

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

Comments

1

Consolidating the comments of @Barmar and the answer of @ikegami, we get:

#include "stdio.h"
#include "stdint.h"

typedef struct MYSTRUCT_S MYSTRUCT;

typedef struct MYSTRUCT_S {
  int (*isInRange)(const MYSTRUCT* pDataPoint, const uint16_t newValue);
  const uint16_t minValue;
  const uint16_t maxValue;
} MYSTRUCT_S;

int isInRange(const MYSTRUCT* pDataPoint, const uint16_t newValue);

int specificImplementation(const MYSTRUCT* pDataPoint, const uint16_t newValue) {
    return 42;
}

int main() {
static MYSTRUCT maDataPoint = {&specificImplementation, 0, 100};

return maDataPoint.isInRange(&maDataPoint, 6);
}

In the above example, maDataPoint is an instance of MYSTRUCT which gets initialized to reference specificImplementation which is a function with the same signature as the declaration of isInRange. The compiler checks for us that specificImplementation matches the signature (both arguments and return type) of isInRange.

1 Comment

typedef struct MYSTRUCT_S { ... } MYSTRUCT_S; should be struct MYSTRUCT_S { ... };.
1

The type definition of MYSTRUCT in your currently code is incomplete. Try to ensure that the type you are referencing is fully defined before using it.

typedef struct MYSTRUCT_S {
  int (*isInRange)(const struct MYSTRUCT_S* pDataPoint, const uint16_t newValue);
  const uint16_t minValue;
  const uint16_t maxValue;
} MYSTRUCT;

int isInRange(const MYSTRUCT* pDataPoint, const uint16_t newValue) {
    if ((newValue < pDataPoint->minValue) || (newValue > pDataPoint->maxValue)) {
        return 0;
    } else {
        return 1;
    }
}

int main() {
    static MYSTRUCT maDataPoint = {isInRange, 0, 10};
    int result = maDataPoint.isInRange(&maDataPoint, 6);
    printf("Result: %d\n", result);
    return 0;
}

Comments

0

Many improvements:

  1. Replace headers "stdio.h" and "stdint.h" with <stdio.h> and <stdint.h>.
  2. Include <stdbool.h> to be able to use true/false.
  3. Include <stdlib.h> to use malloc.
  4. Define struct like this:
    typedef struct MYSTRUCT_S
    {
      // ...
    } MYSTRUCT;
    
  5. Make minValue and maxValue as non-const (doesn't seem to compile with const)
  6. Change return type of function pointer to bool.
  7. Change type of first parameter of function pointer to const struct MYSTRUCT_S*.
  8. Remove line since it's useless: MYSTRUCT* mDatapoint = (MYSTRUCT*)pDataPoint;
  9. Rename the global function (not the one inside struct) name to isInRangeFunPtr.
  10. Replace if-else checks with a single line in function:
    return (newValue >= pDataPoint->minValue) && (newValue <= pDataPoint->maxValue);
    
  11. Add a check for NULL inside the global function. If NULL return false.
  12. Use malloc to create an object inside main. Check if it's NULL, if yes, then return 1.
  13. Assign the global function to function pointer and fill the min and max values.
  14. Test using sample inputs.
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>

typedef struct MYSTRUCT_S
{
  bool (*isInRange)(const struct MYSTRUCT_S* pDataPoint, const uint16_t newValue);
  uint16_t minValue;
  uint16_t maxValue;
} MYSTRUCT;

bool isInRangeFnPtr(const MYSTRUCT* pDataPoint, const uint16_t newValue)
{
    if (pDataPoint == NULL)
    {
        return false;
    }
    return (newValue >= pDataPoint->minValue) && (newValue <= pDataPoint->maxValue);
}

int main()
{
    MYSTRUCT* maDataPoint = malloc(sizeof(MYSTRUCT));
    if (maDataPoint == NULL)
    {
        return 1;
    }
    maDataPoint->isInRange = isInRangeFnPtr;
    maDataPoint->minValue = 19;
    maDataPoint->maxValue = 21;
    printf("Is in range 20? %s\n", maDataPoint->isInRange(maDataPoint, 20) ? "true" : "false");
    printf("Is in range 22? %s\n", maDataPoint->isInRange(maDataPoint, 22) ? "true" : "false");
    return 0;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.