-1

So suppose I have the following two files:

// main.h

struct Player {

    int health;
    int stamina;

};
// main.c

#include "main.h"
#include <stdio.h>

int main() {

    struct Player newPlayer;
    newPlayer.health = 100;
    newPlayer.stamina = 100;

    return 0;
}

This works fine.

Now suppose I have these two files:

// main.h

struct Player {

    int health;
    int stamina;

};

struct Player defaultPlayer;
defaultPlayer.health = 100;  // error here
defaultPlayer.stamina = 100; // error here
// main.c

#include "main.h"
#include <stdio.h>

int main() {

    struct Player newPlayer = defaultPlayer;
    return 0;
}

The error in question is:

Unknown type name 'defaultPlayer'
[clang: unknown_typename]

My question is: Why can't I define a default struct in the .h file?

peki
  • 669
  • 7
  • 24
  • 1
    You are defining a global variable. You can interpret that as a "default", but to the compiler, it's just an instance of the struct. You could initialize that instance, but note that it is not advisable to define global variables in a header. If multiple files include that header, they will all get their own copy. – Emanuel P Apr 15 '21 at 10:56
  • 2
    how would you get to those statements to run them? Execution starts at main. – stark Apr 15 '21 at 11:10

2 Answers2

2

You cannot assign values to members at the file scope because only declarations and definitions are allowed on the scope level. While defaultPlayer.health = 100 is an expression.

To set default values put it into struct initializer:

struct Player defaultPlayer = {
  .health = 100,
  .stamina = 100,
};

Moreover it may be a good idea to make it const.

You can make it an extern symbol. The defaultPlayer would only be declared in main.h and defined main.c.

// main.h
extern const struct Player defaultPlayer;

//main.c
const struct Player defaultPlayer = {
  .health = 100,
  .stamina = 100,
};

Cons: the compiler cannot inline values of members for translation units other than main.c.

Or use a static object in the header.

// main.h
static const struct Player defaultPlayer = {
  .health = 100,
  .stamina = 100,
};

Cons: compiler may complain about unused variables. What can be silenced by adding a dummy function:

static inline void dummy(void) { (void)&defaultPlayer; }

The third option is to make it a macro that expands to the compound literal.

#define defaultPlayer (const struct Player){ .health = 100, .stamina = 100 }

IMO, works the best.

tstanisl
  • 13,520
  • 2
  • 25
  • 40
1

A naive try:

A header defines the interface the object will offer to other objects. Therefore it should not contain any implementation detail.

Imagine you have the following files:

/* pretty_print.h */
// header guard
void pretty_print(char* str);

/* pretty_print.c */
#include <stdio.h>
#include "pretty_print.h"
void pretty_print(char* str) {
    printf("%s", str);
}
#include "pretty_print.h"
int main() {
    pretty_print("Hey there");
}

There will be two objects generated: main.o and pretty_print.o
None of which is yet executable. Neither does main.o contain any function pretty_print.
Linking both together will provide main.o the necessary pretty_print function (as well as do some more stuff).

Now assume there is some sort of data, let's say int x in the pretty_print.h .
As main.o included the header file, there will be such an x. However, pretty_print.o will have an x as well, as it includes pretty_print.h. So there will be two x and the compiler can't know which one to choose.

But I can declare the struct, I just can't change it's values

Yes you can, but you shouldn't declare instances in headers.
To answer, why you can't change it's values, remember there is a main function. When is this "global code" in your execution path? When is it intended to be run?

Please just fix...

You can always use struct initialization in the following way:

struct foo_t {
    int x;
};
struct foo_t foo = { .x = 42 };

If you run in any further errors I assume you have to use the extern keyword with a pointer to a player-struct and initalize it with a default player in main

gkhaos
  • 694
  • 9
  • 20