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?

3
  • Does this answer your question? Why should we typedef a struct so often in C? Commented Feb 26, 2020 at 9: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. Commented Feb 26, 2020 at 9:32
  • But why does just not to include "link.h" work? Commented Feb 26, 2020 at 10:08

2 Answers 2

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]

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

2 Comments

Single underscores are okay, but unnecessary in this case.
@FrankYi Because when you do e.g. struct Token* elem; you also forward declare struct Token.
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

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.