1

I've made 3 files to organize my code. A main.c, a functions.h and a functions.c. I've also made a structure to use with some functions, and I'm having the problem that I can't find any way to declare the functions that use the structures in the .h file. The only way it works is when I put the functions in the .c with the structures without declaring any of them in the .h.

I tried this

in the main just:

#include "functions.c"

and in the .c:

#include "functions.h"
void myfunction(sinWave *sw, float u, float ts){
};

typedef struct{
   float amplitude;
   float fase;
} sinWave;

in the .h:

typedef struct sinWave;

void myfunction(sinWave *, float, float);

But it does not work. I get:

warning: useless storage class specifier in empty declaration
'typedef struct sinWave;'a

unknown type name 'sinWave'
'void ePLL(sinWave , float , float);'
Barmar
  • 741,623
  • 53
  • 500
  • 612
Gabriel Machado
  • 401
  • 3
  • 14
  • 3
    It's rarely correct to using `#include` with a `.c` file. You normally only include `.h` files. – Barmar Jul 15 '19 at 20:07
  • There may be extraordinary cases that need to do things in unusual ways, but this isn't one of them. Put the struct declaration and the function prototypes in the .h file, and the function definitions in the .c file, which includes the .h. Also, you probably want to use double rather than float, unless you have a good reason not to. – Lee Daniel Crocker Jul 15 '19 at 20:14
  • What platform are you on (Linux, Windows, or...)? What build system (Makefiles, SCons, Visual Studio IDE, or...)? Or are you invoking the compiler manually at the command line? Most (all?) of the answers here assume you're using a build system. If you are (for example) just calling GCC from the command line and specifying a single .c file, then running the resulting a.out or a.exe program, then you'll want to start using a build system that will link several object files into a single executable. You can do the same from the command line without a build system but build systems are better. – phonetagger Jul 15 '19 at 20:53
  • Lee Daniel, I'm going to put this on a esp32 with a 32 bits CPU, and I also made another experiments and the double precision does not help me in this case. – Gabriel Machado Jul 15 '19 at 21:34
  • I'm on windows and I'm compiling just gcc main.c -o main.exe – Gabriel Machado Jul 15 '19 at 21:35

4 Answers4

4

Just do it the normal way:

// functions.h
// type declaration
typedef struct { . . . } sinWave;

// function prototype
void myfunction(sinWave *, float, float);

and

// functions.c
#include "functions.h"

void myfunction(sinWave *sw, float u, float ts) {
   // function definition here
}
Lee Daniel Crocker
  • 12,927
  • 3
  • 29
  • 55
  • Putting the definition of the structure in functions.h exposes it to main.c and other translation units, which is generally undesirable if other translation units do not need to know its contents. It is better to identify it with a tag and isolate the full definition to functions.h. – Eric Postpischil Jul 15 '19 at 20:26
  • 1
    True. That's still the "normal" way to do it in C, which has always been more about performance than niceties like information hiding. – Lee Daniel Crocker Jul 15 '19 at 21:35
  • Declaring a pointer to a structure without defining the structure is entirely normal. There is nothing about defining it being “normal” that makes it preferred. OP showed code that did not expose the definition and did not request to expose the definition, so exposing the definition should not be added in a solution. – Eric Postpischil Jul 15 '19 at 23:23
2

Do not include .c, is very bad style, make it visible in the header

In functions.h:

typedef struct sinWave sinWave;

void myfunction(sinWave *, float, float);

In functions.c:

#include "functions.h"

struct sinWave {
   float amplitude;
   float fase;
};

void myfunction(sinWave *sw, float u, float ts) {

}

In main.c:

#include "functions.h"
David Ranieri
  • 39,972
  • 7
  • 52
  • 94
  • `typedef` itself solves nothing at all (though it also doesn't cause any particular trouble here, either). Forward-declaring the `struct type` *probably* doesn't do what the OP needs, especially not positioned as shown in this answer. – John Bollinger Jul 15 '19 at 20:22
  • @JohnBollinger ... well, OP is also using a `typedef` and thats why a use a `typedef`, the problem is that `sinWave` is unknow in the prototype of the function and this is a way to make it visible, whats wrong with the answer? – David Ranieri Jul 15 '19 at 20:25
  • The problem is that the definition of type `struct sinWave` needs to be in scope wherever its size needs to be known or its members need to be accessed. Where only a forward declaration is in scope, it's an "incomplete type". And in your example code, because of its placement, the definition of `struct sinWave` is in scope only for the following semicolon. – John Bollinger Jul 15 '19 at 20:30
  • As far as I can see in his code, OP doesn't need to know the size (is fine to use an incomplete type) – David Ranieri Jul 15 '19 at 20:31
  • He needs to know it if he wants to declare an object of that type (so as to pass a pointer to that object as an argument to the function). And the function needs a complete type in scope, too, if it's going to access the structure members, as seems to be the intent. – John Bollinger Jul 15 '19 at 20:33
  • I agree, but in this case OP is not using any member, I mean this code compiles as is, but you are right, it seems that the intention is to use the members in the function, edited. – David Ranieri Jul 15 '19 at 20:38
2

Like this is better:

main.c:

#include "functions.h"

int main() {
    // ...
}

functions.h:

typedef struct {
    float amplitude;
    float fase;
} sinWave;

void myfunction(sinWave *, float, float);

functions.c:

#include "functions.h"

void myfunction(sinWave *sw, float u, float ts) {
    // ...
};

Build like this (assuming you'll be using sin, cos, etc.):

gcc -o xyz main.c functions.c -lm
  • Putting the definition of the structure in functions.h exposes it to main.c and other translation units, which is generally undesirable if other translation units do not need to know its contents. It is better to identify it with a tag and isolate the full definition to functions.h. – Eric Postpischil Jul 15 '19 at 20:25
  • Yeah, we need to know more about `main` to make that call. –  Jul 15 '19 at 20:32
  • The original code in the question does not attempt to define the structure in functions.h, merely refer to it, so solutions should not add this unrequested exposure. – Eric Postpischil Jul 15 '19 at 20:34
  • 1
    @EricPostpischil, at their apparent level of mastery, it seems unlikely that the OP's intent is to use an opaque structure type. Although we cannot be sure, putting the definition of the structure into functions.h and thus exposing it to `main` is exactly what I anticipate is needed to serve the OP's probable intended use. – John Bollinger Jul 15 '19 at 20:38
  • @JohnBollinger: “Many beginners make that mistake, so we should assume OP wants to make that mistake and show them how” is not a good basis on which to proceed. – Eric Postpischil Jul 15 '19 at 20:40
  • @EricPostpischil, rather than have a debate here and now, I will simply state that I disagree with you about exposing structure type definitions categorically being a mistake. – John Bollinger Jul 15 '19 at 20:44
  • @JohnBollinger: “Many beginners expose a structure needlessly, so we should assume OP wants to expose the structure needlessly and show them how” is not a good basis on which to proceed. – Eric Postpischil Jul 15 '19 at 23:24
  • I wanted, indeed, to be able to access the structure in the main. So I guess he was right about my will to commit mistakes hehehe. But I also want to learn how to make things right. So thank you both. – Gabriel Machado Jul 16 '19 at 04:40
  • 1
    @GabrielMachado A common saying: "Good developers don't make mistakes because they've already made them all." If you like what you've done and think it would be good to hide some structures, functions, etc. ask here, they'll be plenty of advice! –  Jul 16 '19 at 13:22
1

typedef struct sinWave; does not declare a type. It introduces sinWave as a structure tag. A tag is not a type name by itself; it makes struct sinWave a type, but not sinWave by itself. (In C++, it would make sinWave a type.)

To fix this, you need to make two changes. In functions.h, declare sinWave to be a type that is an alias for struct sinWave:

typedef struct sinWave sinWave;

In functions.c, insert a definition of the structure with the tag:

struct sinWave
{
   float amplitude;
   float fase;
};

(You may also want to spell phase correctly.)

Note that you already have a structure definition in function.c:

typedef struct{
   float amplitude;
   float fase;
} sinWave;

There are two problems with this. One is that a structure defined with a tag in one translation unit is not compatible with a structure defined without a tag in another translation unit. And you need to use a tag to identify which structure is being given a name by the typedef (or you could provide a complete definition of the structure with the typedef in function.h, but that is an undesirable solution for other reasons).

The other problem is this definition appears after myfunction, but myfunction might need the definition of the structure, so the definition has to appear before myfunction.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • I'm from Brazil and fase and amplitude are portuguese words. I know I should stop mixing words like this if I want to write profesional code. Thank you for the advices. – Gabriel Machado Jul 16 '19 at 04:50