pycparser: parse back c file - c

i'm trying to learn how to use pycparser and during my practice I encontured this problem.
Basically I have a C file with system header like #include <stdio.h> and #include <stdlib.h> and I want to analyze it through the pycparser ast tree.
I succeded in using the fake headers so i could parse the file but then i got this problem: the ast now contains a lot of typedef and doesn't contain the real headers, so after I print the ast in a file to have my c code back, it can't compile because the real headers are missing.
For example this file:
#include <stdlib.h>
#include <stdio.h>
typedef struct {
//my struct
} NODE;
int main() {
//do stuff
return 0;
}
becomes this:
typedef int size_t;
typedef int __builtin_va_list;
typedef int __gnuc_va_list;
typedef int va_list;
typedef int __int8_t;
....
typedef int __uint64_t;
typedef int __int_least32_t;
typedef int __uint_least32_t;
....
typedef struct xcb_connection_t xcb_connection_t;
typedef uint32_t xcb_window_t;
typedef uint32_t xcb_visualid_t;
//a lot of typedef
typedef struct {
//my struct
} NODE;
int main() {
//do stuff
return 0;
}
Doing my research i saw that #include <stdlib.h> contains the following lines:
#include "_fake_defines.h"
#include "_fake_typedefs.h"
and those headers contain all the typedef that appear in my file.
Is there a way to print back the c code with the real headers?

Related

Use typedef from one header in another and vice versa

Suppose I have such a project structure:
main.c
#include "hashtable.h"
#include "list.h"
int main()
{
hash_table ht = calloc(1, sizeof(htable));
cmp_function f;
TLDI list;
return 0;
}
hashtable.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _HASH_TABLE_
#define _HASH_TABLE_
#include "list.h"
typedef int (*hash_function)(void*, int);
typedef struct _hasht_{
int maxElemNumber;
hash_function hf;
TLDI* key_array;
} htable, *hash_table;
void test2(cmp_function cmp);
#endif
list.h
#include "hashtable.h"
#ifndef _LINKED_LIST_
#define _LINKED_LIST_
typedef int (*cmp_function)(void*, void*);
typedef struct _node_ {
void *info;
struct _node_ *pre, *urm;
} TNode, *TLDI;
int test(hash_table ht);
#endif
and another two C files:
hash_func.c
#include "hashtable.h"
void test2(cmp_function cmp)
{
printf("test\n");
}
list_func.c
#include "list.h"
int test(hash_table ht)
{
return 1;
}
I want to use in hashtable.h a typedef from list.h, it's typedef struct...},*TLDI;. In the same way, list.h uses a typedef struct ...},*hash_table; from hashtable.h. Can I do something like this or I'm wrong? Cause I get this error while compiling whole project:
In file included from hashtable.h:7,
from main.c:1:
list.h:14:10: error: unknown type name ‘hash_table’
14 | int test(hash_table ht);
In file included from hashtable.h:7,
from hash_func.c:1:
list.h:14:10: error: unknown type name ‘hash_table’
14 | int test(hash_table ht);
I'm not strong in typedef and headers, but if I would get an answer to this question or at least a source from where I could find out more about them I would be very grateful.
Two headers that rely to each other are not a show stopper if well-formed. What I observe is that your include guards don't enclose the full header but only part of it, this I think is wrong. The right way to use include guards is shown in this
example header some_component.h:
#ifndef SOME_COMPONENT_H
#define SOME_COMPONENT_H
// include whatever you need here (*after* the opening guard):
#include "some_other_component.h"
// start type definitions and declarations *after* includes:
struct some_component_t {
// ...
};
#endif
This way, you headers will work most consistently:
either read completely
or completely ignored
I advise you to avoid placing definitions before includes, as this allows you to modify the content of the included content. What looks like a tempting idea at first, turns into a confusing nightmare in the long run in the vast majority of cases.
Another point is that if the definitions in the two headers really rely on each other, you should rethink your design.
Also, it's not clear why void test2(cmp_function cmp); which relies on cmp_function is declared in hashtable.h and why int test(hash_table ht); which relies on hash_table is declared in list.h; to me this seems like you were mixing up things here. In other words, by switching places of some declarations, you'd get rid of most of the entanglement.
You should also know that typedefs and pointers are allowed on incomplete types, so it's possible to declare a pointer to a structure that is not yet defined. So, for example, the following compiles:
typedef int (*hash_function)(void*,int);
typedef int (*cmp_function)(void*,void*);
typedef struct _hasht_ hasht, *hash_table;
typedef struct _node_ TNode, *TLDI;
struct _node_ {
void *info;
struct _node_ *pre, *urm;
};
struct _hasht_{
int maxElemNumber;
hash_function hf;
TLDI* key_array;
};
... as does this (version without struct typedefs):
struct _node_ {
void *info;
struct _node_ *pre, *urm;
};
typedef int (*hash_function)(void*,int);
struct _hasht_{
int maxElemNumber;
hash_function hf;
struct _node_** key_array;
};
The overall interdependency of the headers is kind of ugly, but the errors can be corrected with some forward declarations:
hashtable.h
#ifndef _HASH_TABLE_
#define _HASH_TABLE_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct _hasht_ htable, *hash_table;
typedef int (*hash_function)(void*,int);
#include "list.h"
struct _hasht_ {
int maxElemNumber;
hash_function hf;
TLDI* key_array;
};
void test2(cmp_function cmp);
#endif
list.h
#ifndef _LINKED_LIST_
#define _LINKED_LIST_
typedef struct _node_ TNode, *TLDI;
typedef int (*cmp_function)(void*,void*);
#include "hashtable.h"
struct _node_ {
void *info;
struct _node_ *pre, *urm;
};
int test(hash_table ht);
#endif

How to use a function of a struct in another struct?

i'm doing a simple project in C in which, for the moment, i use two structs: Player and Card.
I have created the 2 struct in different header files, because functions in Player use Card, but also other elements that I haven't already done.
When I try to use getId() in Player, the VSCode's compiler says:
reference to external symbol _getId not resolved in _discardCard()
card.h code is:
#include <stdbool.h>
typedef struct card{
int id;
bool black;
int numElems;
char* text[3];
}card;
card* initCard(int id,bool black,char* text[],int numElems)
int getId(card* c);
card.c code is:
#include "carta.h"
#include<stdio.h>
#include <stdbool.h>
#include <stdlib.h>
...
int getId(carta* c){
return c->id;
}
Instead the code for Player.h is:
#include "card.h"
#define CARDSMAX 5
typedef struct{
bool master;
int id;
int points;
char* nickname;
card* cards[CARDSMAX];
int NumCards;
}player;
... //other functions
card* discardCard(int id,player* g);
The code for Player.c is:
#include "player.h"
#include <stdio.h>
#include <stdlib.h>
player* initPlayer(char* nickname,int id){
player* g=(player*) malloc(sizeof (player));
g->id=id;
g->nickname=nickname;
g->master=false;
g->points=0;
g->NumCards=0;
for(int i=0;i<CARDSMAX;i++){
g->cards[i]=(card*)malloc(sizeof(card));
}
return g;
}
....
card* DiscardCard(int id,player* g){
for(int i=0;i<CARDSMAX;i++){
card* c=g->cards[i];
if(getId(c)==id){
card* e= g->cards[i];
g->cards[i]=NULL;
g->NumCards--;
return e;
}
}
return NULL;
}
Can someone help me? (If you see some inconsistency in the code, it'is because i tried a fast translation from my language)
So, as suggested , the problem was that in Windows' compiler, when you use struct that use function defined in other structs,it is required to pass the .obj file during the compilation .
For doing this you need to compile every .c file that is used by others singulary and then link the .obj file created in this fase.
So in my case the first step is to compile:
cl card.c
that create a card.obj (the Windows' compiler could show you a message that says something like:"The start point is not indicated" if you don't use a main in this first file, don't worry and carry on with this procedure) and then I compile:
cl player.c /link card.obj
So in this way you pass the compiled object in which it's provided the implementation of all the function in the struct.

Problems compiling in C, while included doesnt detect a struct

i´m trying to compile 3 files in C. One is main.c, where i declare the variables, another is cuenta.h and the other is cliente.h. cuenta.h has a struct used in another struct in cliente.h, but this error appears. How can I solve this? Thanks!
cliente.h
#ifndef PACABANK_CLIENTE_H
#define PACABANK_CLIENTE_H
#include "cuenta.h"
#include "fecha.h"
typedef struct {
char *dni;
char *titular;
Tarjeta tarjeta;
}InfoCliente;
cuenta.h
#ifndef PACABANK_CUENTA_H
#define PACABANK_CUENTA_H
#include "cliente.h"
#include "fecha.h"
typedef struct
{
int numero_tarjeta;
char *iban;
Fecha caducidad;
char *nombre_titular;
int cvv;
char *tipo; //mastercard, visa, american express.....
float limite;
}Tarjeta;
The error
In file included from cuenta.h:7:0,
from cuenta.c:5:
cliente.h:14:5: error: unknown type name 'Tarjeta'
Tarjeta tarjeta;

"unknown type name" in c struct while ussing gcc

I have a program which is processing list in c, it is working perfectly as long as I have it in one source file, when I try to separate it and compile it got this error “ delete_functions.c:15:13: error: unknown type name ‘nodetype’ ” same error goes for functionality_functions.c and insert_functions.c here is the code
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "delete_functions.h"
#include "insert_functions.h"
#include "functionality_functions.h"
int main(){
//i did not upload all the main function code because it is way to long
}
types.h
typedef char AirportCode[4];
typedef struct nodetype{
char Airport[4];
struct nodetype *next;
} nodetype;
delete_functions.h
void Delete(nodetype *list,char node[4]);
void DeleteLast(nodetype *list);
functionality_functions.h
void print(nodetype *head);
nodetype *search(nodetype *list,char item[4]);
nodetype *create();
insert_functions.h
void *InsertLast(nodetype *list,char item[4]);
void *InsertAfter(nodetype *list,char item[4],char node[4]);
According to the GCC error message, there error is in the delete_functions.c file.
Presumably, it looks like this at the beginning:
#include "delete_functions.h"
Since delete_functions.h does not itself include types.h, you need to include it first:
#include "types.h"
#include "delete_functions.h"
Alternatively, you can add include guards to your headers so, that they can safely be included multiple times, like this for types.h:
#ifndef TYPES_H
#define TYPES_H
typedef char AirportCode[4];
typedef struct nodetype{
char Airport[4];
struct nodetype *next;
} nodetype;
#endif
And for delete_functions.h:
#ifndef DELETE_FUNCTIONS_H
#define DELETE_FUNCTIONS_H
void Delete(nodetype *list,char node[4]);
void DeleteLast(nodetype *list);
#endif
The *_H include guard macros are necessary because otherwise, main.c would not compile anymore: each type in types.h can only be defined once per translation unit, and without the guards, every *.h would bring in another definition, leading to compiler errors.

C Error C2371 redefinition

Error 2 error C2371: 'QixC': redefinition; different basic types line 5
Error 5 error C2371: 'QixC': redefinition; different basic types line 5
Error 13 error C2371: 'QixC': redefinition; different basic types line 5
This is the part of the file Game.h:
#include "Graphics_Console.h"
#include <stdio.h>
#include <conio.h>
typedef struct
{
int X;
int Y;
}QixC;
typedef struct
{
int X;
int Y;
}CCursor;
And I use them in Game.c :
#include "Game.h"
#include <stdio.h>
#include <conio.h>
#include <time.h>
int QIX(int nivell)
{
QixC Qix;
CCursor Cursor;
HANDLE hScreen;
int DirQixX,DirQixY;
int IniciX,IniciY;
int FiX, FiY;
int DirStix=0;
int Area=0,AreaTotal=0,AreaObjectiu=(FI_X-INICI_X)*(FI_Y-INICI_Y)*0.75;
int Pantalla=1;
int Puntuacio=0;
int tecla=0;
int viu=1;
int NCops=0, Velocitat=1000/(nivell*0.70);
int XocStix=0;
char continuar[1];
hScreen = GetStdHandle(STD_OUTPUT_HANDLE);
InitScreen(hScreen);
do
{
system("CLS");
IniciX=INICI_X,IniciY=INICI_Y;
FiX=FI_X, FiY=FI_Y;
Cursor.X=INICI_X+(FiX-INICI_Y)/2,Cursor.Y=FI_Y;
DibuixarRectangle(IniciX,IniciY,FI_X,FI_Y,hScreen);
InfoPuntsPartida(hScreen, Puntuacio);
InfoPantallaPartida(hScreen, Pantalla);
Qix.X=Aleatori(IniciX+1,FiX-1),Qix.Y=Aleatori(IniciY+1,FiY-1);
InicialitzarDirQix(&DirQixX,&DirQixY);
PintarQix(Qix,hScreen);
PintarCursor(Cursor.X,Cursor.Y,hScreen);
do{
if(_kbhit())
{
tecla=LlegirEvent();
TractarEvent(tecla,Cursor,&IniciX,&IniciY,&FiX,&FiY,Qix,&DirStix,&Area,hScreen);
if(Area)
{
Puntuacio=Puntuacio+Area;
AreaTotal+=Area;
Area=0;
InfoPuntsPartida(hScreen,Puntuacio);
}
}
NCops++;
if(NCops==Velocitat)
{
if(DirStix!=0)
XocStix=QiXXocStiX(Qix,Cursor,DirStix);
if(!XocStix)
MoureQix(Qix,&DirQixX,&DirQixY,IniciX,IniciY,FiX,FiY,hScreen);
else
viu=0;
NCops=0;
}
}while((tecla!=TECLA_q)&&(tecla!=TECLA_Q)&&viu &&(AreaTotal<AreaObjectiu));
GameOver(hScreen);
TextColor(LIGHTGREY,BLACK,hScreen);
GotoXY(0,FI_Y+1,hScreen);
return Puntuacio;
system ("PAUSE");
printf("Continuar?(s/n)");
scanf("%c",&continuar);
}while(continuar!="s");
}
Sorry for the foreign words and names, english is not my first language.
I can't see where is redefined. They don't appear anywhere else,but are passed as parameters to some functions. Any help, please?
Try guarding your header against multiple inclusion.
#ifndef GAME_H
#define GAME_H
#include "Graphics_Console.h"
#include <stdio.h>
#include <conio.h>
typedef struct
{
int X;
int Y;
}QixC;
typedef struct
{
int X;
int Y;
}CCursor;
#endif /* GAME_H */
By default, if you include multiple headers which directly or indirectly include your header, you'll get multiple competing (if identical) versions of its structures and functions. You can avoid this by starting your header
#ifndef SOMETHING_UNIQUE_TO_YOUR_HEADER
#define SOMETHING_UNIQUE_TO_YOUR_HEADER
and ending it
#endif /* SOMETHING_UNIQUE_TO_YOUR_HEADER */
which guarantees that any source file will include at most a single copy of your structures.

Resources