2

I have a problem in my code.

Here is my demo:

My file structure is

├── include
│   ├── link.h
│   └── token.h
└── src
    ├── CMakeLists.txt
    └── main.c
//token.h

#ifndef __TOKEN_H__
#define __TOKEN_H__
#include <stdio.h>
#include "link.h"

typedef struct Token{
    char val[30];
}token;

#endif
//link.h

#ifndef __LINKLIST_H__
#define __LINKLIST_H__
#include <stdio.h>
#include "token.h"

typedef struct Linklist{
    token* elem;          
    struct Linklist *next;  
}linklist;

#endif
//main.c

#include <stdio.h>
#include "token.h"
#include "link.h"
#include <stdlib.h>
#include <string.h>

int main(){
    linklist* head = (linklist*)malloc(sizeof(linklist));
    head->elem = (token*)malloc(sizeof(token));
    strcpy(head->elem->val, "111");
    printf("%s\n", head->elem->val);
}
//CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0)
project(test VERSION 0.1.0)

include_directories(../include)

add_executable(test main.c)

Enter the src file and compile this demo

mkdir build && cd build 
cmake ..
make

Then one error occurs:

error: 
      unknown type name 'token'
    token* elem;          
    ^
1 error generated.

But we don't use typedef, just use the struct Token, everything will be ok.

The modification version is:

//token.h

struct Token{
    char val[30];
};

//link.h

typedef struct Linklist{
    struct Token* elem;          
    struct Linklist *next; 
}linklist;
//main.c

head->elem = (struct Token*)malloc(sizeof(struct Token));

I want to ask why does this situation happen?

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
FrankYi
  • 21
  • 3
  • Does this answer your question? [Why should we typedef a struct so often in C?](https://stackoverflow.com/questions/252780/why-should-we-typedef-a-struct-so-often-in-c) – PiRocks Feb 26 '20 at 09:29
  • 2
    In contrast to the answers, the core of the problem here is _not_ a circular dependency, but simply that, due to the order of includes, the type `token` is used before the `typedef` of it. – Ctx Feb 26 '20 at 09:32
  • But why does just not to include "link.h" work? – FrankYi Feb 26 '20 at 10:08

2 Answers2

4

You have a circular inclusion dependency, and you need to break this circle.

The common way to do it is to stop including files in header file where it's not really needed, and use forward declarations when needed.

One simple way with your current code is to simply not include link.h in tokens.h, since struct Linklist or linklist is not used in the token.h header file:

#ifndef TOKEN_H
#define TOKEN_H

typedef struct Token{
    char val[30];
}token;

#endif

Note that there's no #include directives above.


On another note I changed the header-guard macro names, because all symbols with double-underscore are reserved in C, you should not define such symbols or names yourself (as macros or otherwise).

From this reserved identifiers reference:

All identifiers that begin with an underscore followed by a capital letter or by another underscore

[Emphasis mine]

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
0

It's happening because you created a circular dependency by including link.h in token.h and vice versa.

If you cut the #include <link.h> from token.h everything should work just fine.

When you #include token.h in your main, here's what's going to happen:

#ifndef __TOKEN_H__ //not defined
#define __TOKEN_H__
#include <stdio.h>
//#include "link.h" expands to:

  #ifndef __LINKLIST_H__ //not defined
  #define __LINKLIST_H__
  #include <stdio.h>
  //#include "token.h" expands to:

    #ifndef __TOKEN_H__ //defined
    #endif

  typedef struct Linklist{
      token* elem;          // token was not declared yet: ERROR
      struct Linklist *next;  
  }linklist;

  #endif 

typedef struct Token{
    char val[30];
}token;

#endif
sephiroth
  • 896
  • 12
  • 22