Conflicting types of function across multiple files

Viewed 347

Ive been getting an error for every single function within my code that reads:

database.c:21:5: error: conflicting types for ‘p_register’
   21 | int p_register (struct unPaciente *tabla, int *numero) {
      |     ^~~~~~~~~~
In file included from database.c:11:
database.h:20:5: note: previous declaration of ‘p_register’ was here
   20 | int p_register (struct unPaciente *tabla, int *numero);

I have a file called database.c which needs to take the prototypes of other functions from other files, which are called database.h, and inout.h. The code for each of this files are as follows:

database.c

//DEFINICIONES DE LAS FUNCIONES

//Generacion de un ejecutable a partir de dos codigos fuentes -> gcc -Wall divoc.c inout.c -o divoc

//Generacion del codigo objeto de inout -> gcc -Wall -c inout.c

//Generacion de un ejecutable a partir de un codigo fuente y un codigo objeto -> gcc -Wall divoc.c inout.o -o divoc



#include "database.h"
#include "inout.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>



//DEFINICION DE FUNCIONES del menú

int p_register (struct unPaciente *tabla, int *numero) { 

int i;
int verificacion;
int tos, fiebre;
i = *numero;
int *ptos, *pfiebre;
char sintomas;
char *p;
p = &tabla[i]; //puntero que apunta a la direccion de losPacientes



fprintf (stdout ,"Register \n");
get_string ("Name (1-24)",1, 25, tabla[i].nombre); //Pide un nombre con get_string y lo guarda en tabla[numero].nombre 
do {
get_string ("DNI (9-9)", 9, 9, tabla[i].dni); //pedir dni con get_string y guardarlo en tabla[numero].dni
verificacion = verify_dni(tabla[i].dni);
if (verificacion == 0) {
fprintf (stdout ,"Invalid DNI \n");
}
} while (verificacion == 0); 


get_integer ("Date [1900-2020]", 0,120); //pedir edad con get_integer y guardarlo en tabla[numero].edad


tos = yes_or_no("Cough (y/n): "); //preguntar si tienes tos con yes_or_no y guardarlo en tabla[numero].tos
(*p).tos = tos;


fiebre = yes_or_no("Fever (y/n): "); //preguntar si tiene fiebre con yes_or_no y guardarlo en tabla[numero].fiebre
(*p).fiebre = fiebre;

sintomas = get_caracter("Sypmtom", "FSTMN");
(*p).sintomas = sintomas;

fprintf (stdout ,"New patient: %s %s %d %d %d %c \n",tabla[i].nombre, tabla[i].dni, tabla[i].edad, tabla[i].tos, tabla[i].fiebre, tabla[i].sintomas); 
 
numero += 1;
return numero;
}




int p_discharge (struct unPaciente *tabla, int *numero) {                   //Funcion p_discharge.

fprintf (stdout ,"Discharge \n");

int n;
char *dni;
int longitud;
int i;

char *a, *aaux;
char *b, *baux;
char *c, *caux;
char *d, *daux;
char *e, *eaux;
char *f, *faux;


aaux = &tabla[i].nombre;
baux = &tabla[i].dni;
caux = &tabla[i].edad;
daux = &tabla[i].tos;
eaux = &tabla[i].fiebre;
faux = &tabla[i].sintomas;

*aaux = (char*)malloc(25 * sizeof(char));
*baux = (char*) malloc (10 * sizeof(char));
 
if (numero == 0) {                          //Comprueba si hay pacientes registrados que poder eliminar
fprintf (stdout ,"No patients yet \n");
return 0;
}

do {
get_string("DNI (9-9): ",9 ,9 ,dni);
longitud = strlen(dni);
} while (longitud != 9);

for (i=0; i <= *numero; i++) { //Recorre la tabla en busca de un paciente con un dni igual al introducido por el usuario
  
if ((dni == tabla[i].dni) && (i != numero)) { //SI SE QUIERE ELIMINAR UN PACIENTE DE EL MEDIO DE LA LISTA
for (i = i; i < *numero; i++) {

                
*aaux = tabla[i+1].nombre;
*baux = tabla[i+1].dni;
*caux = tabla[i+1].edad;
*daux = tabla[i+1].tos;
*eaux = tabla[i+1].fiebre;
*faux = tabla[i+1].sintomas;

//Por si es necesario borrar la memoria del ultimo elemento(ahora vacio despues de sobreescribir) 
//free(aaux);
//free(baux);
//free(caux);
//free(daux);
//free(eaux);
//free(faux);
}
}



if ((dni == tabla[i].dni) && (i == *numero)) { //SI SE QUIERE ELIMINAR EL ULTIMO PACIENTE DE LA LISTA
a = &tabla[i].nombre;
b = &tabla[i].dni;
c = &tabla[i].edad;
d = &tabla[i].tos;
e = &tabla[i].fiebre;
f = &tabla[i].sintomas; /////ARREGLAR ESTA PARTE 

free(a);
free(b);
free(c);
free(d);
free(e);
free(f);

fprintf (stdout, "Discharged patient \n");
numero -= 1;
return numero;
}
else {
fprintf (stdout ,"Unknown patient \n");
return numero;
}
}
}



int p_list(struct unPaciente *tabla, int numero) {                  
    
    
    
    int i;
    int edad;
    fprintf (stdout ,"List \n"); 
    edad = get_integer("Date [1900-2020]",0, 120); //Pide al usuario hasta que edad quiere que busque pacientes
    fprintf (stdout ,"Patients born before %d", edad);
    for (i = 0; i < numero; i++) { //Recorre la tabla, desde el 0, hasta el numero de pacientes
    if (tabla[i].edad <= edad) {
    display_patient(tabla, i);  //Comprueba si algun paciente de la tabla tiene una fecha de nacimiento menor o igual que la dada por el usuario, y si es el caso, imprime su info 
    }
    

return 1;
}
}




int p_search (struct unPaciente *tabla, int numero) {                   //Funcion p_search.

    


    int i;
    char dni[10];
    fprintf (stdout ,"Search \n");
    get_string("DNI:",9 ,9 ,dni);     //Pide al usuario un DNI con la funcion get_string
    for (i = 0; i <= numero; i++) {
    if (dni == tabla[i].dni) //Recorre la tabla en busca de una coincidencia con el dni introducido, si la hay, imprime su info
    display_patient(tabla, i);
    else {
    fprintf (stdout ,"No matches \n"); //Informa al usuario que no hay ningun paciente que coincida con el dni introducido
    }
    return 0;
}   
}





void p_mark (struct unPaciente *tabla, int numero) { //Funcion p_mark


int i;
fprintf (stdout ,"Mark positive \n"); //Indica al usuario que ha entrado en la funcion mark positive

if (numero == 0) { //Comprueba si el numero de pacientes es igual a 0
fprintf (stdout, "No patients yet \n");
return;
}

for (i=0; i <= numero; i++) { //Recorre la tabla en busca de un paciente que padezca de algun sintoma o enfermedad, y si lo encuentra, imprime sus datos

if ((tabla[i].tos == 1) || (tabla[i].fiebre == 1) || (tabla[i].sintomas == 'F') || (tabla[i].sintomas == 'S') || (tabla[i].sintomas == 'T')|| (tabla[i].sintomas == 'M')|| (tabla[i].sintomas == 'N')) {

fprintf (stdout ,"%s %s %d %d %d %c \n",tabla[i].nombre, tabla[i].dni, tabla[i].edad, tabla[i].tos, tabla[i].fiebre, tabla[i].sintomas);
return;
}

else { 
fprintf (stdout ,"No sick patients yet \n"); //Si no hay un paciente que cumpla alguna de las condiciones anteriores, informa al usuario que no hay pacientes enfermos
return;
}
}
}

//int p_init (struct unPaciente *tabla, int numero) {
//  int edad;
    



//  numero = 0;
//  edad = get_integer ("Date");
//  while (edad > 1) {
//      tabla[numero].edad = edad;
//      get_string ("Name", 9, 9, tabla[numero].nombre);
//      numero =+ 1;
//      edad = get_integer ("Date");
//  }
//  return 0;
//  }

void save_patients (struct unPaciente *tabla, int numero, FILE *fp) {
int i;



while ((i = fgetc(fp)) != EOF)
    fputc(i, fp);
return;
}

int p_exit () {
int valor_salida;

fprintf (stdout ,"Exit \n");
valor_salida = yes_or_no("Are you sure you want to exit"); //El valor sacado de la funcion yes_or_no (1 o 0) sera atribuído a valor_salida y será el valor devuelto por la función

return valor_salida;
}

Database.h

#ifndef DATABASE_H

#define DATABASE_H
//DECLARACIONES DE LAS FUNCIONES (PROTOTIPOS) del menú



void init_patients (struct unPaciente *tabla, int numero);

void save_patients (struct unPaciente *tabla, int numero, FILE *fp);

//int p_init (struct unPaciente *tabla, int numero); 

int p_discharge (struct unPaciente *tabla, int *numero); 

int p_list(struct unPaciente *tabla, int numero);
 
int p_search (struct unPaciente *tabla, int numero);

int p_register (struct unPaciente *tabla, int *numero); 

void p_mark (struct unPaciente *tabla, int numero); 

int p_exit();

#endif

inout.c (which has the code for some functions used in database.c)

//Generacion de un ejecutable a partir de dos codigos fuentes -> gcc -Wall divoc.c inout.c -o divoc

//Generacion del codigo objeto de inout -> gcc -Wall -c inout.c

//Generacion de un ejecutable a partir de un codigo fuente y un codigo objeto -> gcc -Wall divoc.c inout.o -o divoc




#include "inout.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


//DEFINICION DE FUNCIONES fuera del menú

void headline (char * APLICACION ,char caracterhl, int numchar) {    // Funcion headline. Imprime una cadena centrada, entre 2 caracteres dados por el usuario.
    
int numblanks;
int j;

strlen(APLICACION);
numblanks = ((numchar - 2) - strlen(APLICACION)) /2;
fprintf (stdout ,"%c", caracterhl);
for (j=0; j<numblanks; j++) {
fprintf (stdout ," ");
}
fprintf (stdout ,"%s", APLICACION);

for (j=0; j<numblanks; j++) {
fprintf (stdout ," ");
} //si es impar numblanks, se hace un if else. El if imprime un (espacio) (+) y (cambio de linea) si es impar, y en el else, imprime un (+) y (cambio de linea)

if (numblanks%2 != 0) {

fprintf (stdout ,"%c" ,caracterhl);
fprintf (stdout ,"\n");
}
else {

fprintf (stdout ," ");
fprintf (stdout ,"%c" ,caracterhl);
fprintf (stdout ,"\n");
} 
}

void stripe (char caracter, int numchar) { //funcion stripe modificada
int i;

for (i=0; i<numchar; i++) {
fprintf (stdout ,"%c" ,caracter);
}
if (i == numchar) {
fprintf (stdout ,"\n");
}
return;
}


//funcion yes_or_no

int yes_or_no (char *mensaje) { //YES_OR_NO (CONFIRMACION DE SALIDA) añadir sscanf
char opcion2;


fprintf (stdout ,"%s", mensaje);
fscanf (stdin ," %c", &opcion2);

if ((opcion2 == 'y') || (opcion2 == 'Y'))
    {
        fprintf (stdout ,"Ha seleccionado \"Si\".\n");
    return 1;
    
    }
    
if ((opcion2 == 'n') || (opcion2 == 'N'))
    {
        fprintf (stdout ,"Ha seleccionado \"No\".\n");
    return 0;
    
    }
else 
    { 
        fprintf (stdout ,"No ha seleccionado una opcion valida\n"); 
    return 0;
    
    }
}
//get_string

void get_string(char *mensaje ,int min ,int max ,char *la_cadena) {
    char *linea; 
    char extra[256];
    int valores;
    int longitud, longitud2;    
    char *otra_cadena;
    
    linea = (char *)malloc(max*sizeof(char));
    
    do {
    fprintf (stdout ,"%s" ,mensaje);
    fgets (linea, sizeof(linea), stdin);
    valores = sscanf (linea ,"%s%s" ,otra_cadena ,extra);

    if (valores != 1) {
    fprintf (stdout, "Formato incorrecto\n");
    longitud = 0;
    }

    else {
    longitud = strlen(otra_cadena);
    }
    } while ((longitud < max) && (longitud > min));

longitud2 = strlen(linea); 
linea[longitud2 + 1] = '/0';
strcpy (la_cadena, otra_cadena);
return;
}


//funcion get_integer

int get_integer (char *mensaje, int min, int max) {         //Funcion get_integer. Recibe una cadena como parametro, lee un numero, y devuelve ese numero si esta dentro del rango [1,24]
int numero; 
char extra[256]; //cadena extra para comprobar si se introducen algo más que el número  
int valores;
mensaje = (char *) malloc (256*sizeof(char));
    
do {    
    fprintf (stdout, "%s" ,mensaje);
    fscanf (stdin, "%d" ,&numero);
    
if ((numero >= max) || (numero <= min)) 
{
    fprintf (stdout ,"Valor incorrecto\n");
}

}
while ((numero >= max) || (numero <= min));

valores = sscanf (numero ,"%d%s" ,&numero ,extra);
if (valores == 2)
{
fprintf (stdout, "Formato incorrecto");
return 0;
}

else {
return numero;
}
}

char get_character (char *mensaje, char *comprobacion) {
int valores;
char letra; 
char extra[256]; //cadena extra para comprobar si se introducen algo más que el número  
mensaje = (char *) malloc (256*sizeof(char));

do {
    fprintf (stdout, "%s" ,mensaje); //Se lee el mensaje de invitacion al usuario
    fprintf (stdout ,"%s" ,comprobacion); 
    fscanf (stdin, "%c" ,&letra); //Se escanea el resultado
    valores = sscanf (letra ,"%c %s" ,&letra ,extra); //Se le asigna a valores un numero en funcion del numero de elementos introducidos, si es distinto de 1, dará error
if (valores != 1)
{
fprintf (stdout, "Formato incorrecto");
break; //Si el formato es incorrecto pasará a la siguiente repeticion del bucle, saltándose los dos switch
}

if ((letra != 'F') || (letra != 'f') || (letra != 'S') || (letra != 's') || (letra != 'T') || (letra != 't') || (letra != 'M') || (letra != 'm') || (letra != 'N') || (letra != 'n') || (letra != 'R') || (letra != 'r') || (letra != 'S') || (letra != 's') || (letra != 'D') || (letra != 'd') || (letra != 'P') || (letra != 'p') || (letra != 'L') || (letra != 'l') || (letra != 'X') || (letra != 'x')) {
fprintf (stdout ,"Invalid option \n"); //Se comprueba que la letra es distinta a cualquiera de las letras pertenecientes al menu o a los sintomas
}


if ((letra == 'F') || (letra == 'f') || (letra == 'S') || (letra == 's') || (letra == 'T') || (letra == 't') || (letra == 'M') || (letra == 'm') || (letra == 'N') || (letra == 'n')) {
//Para el caso de que se quiera obtener una letra para los síntomas
switch (letra) {
    case 'F':
    case 'f':
    letra = 'F';
    return letra;
    
    case 'S':
    case 's':
    letra = 'S';
    return letra;
    
    case 'T':
    case 't':
    letra = 'T';
    return letra;
    
    case 'M':
    case 'm':
    letra = 'M';
    return letra;
    
    case 'N':
    case 'n':
    letra = 'L';
    return letra;
    
    default:
    fprintf (stdout ,"Invalid option \n");
    break;

}
}

if ((letra == 'R') || (letra == 'r') || (letra == 'S') || (letra == 's') || (letra == 'D') || (letra == 'd') || (letra == 'P') || (letra == 'p') || (letra == 'L') || (letra == 'l') || (letra == 'X') || (letra == 'x')) {
//Para el caso de que se quiera obtener una letra para el menú
switch (letra) {
    case 'R':
    case 'r':
    letra = 'R';
    return letra;
    
    case 'S':
    case 's':
    letra = 'S';
    return letra;
    
    case 'D':
    case 'd':
    letra = 'T';
    return letra;
    
    case 'P':
    case 'p':
    letra = 'P';
    return letra;
    
    case 'L':
    case 'l':
    letra = 'L';
    return letra;
    
    default:
    fprintf (stdout ,"Invalid option \n");
    break;

}
}
} while (valores !=1); //El bucle se va a repetir siempre y cuando se introduzcan varios elementos (!= 1) o cuando no se introduzca ninguna de las letras deseadas, siendo ese el caso en el que la funcion entrara en el "else", llegando a un break y volviendo a pedir una letra, mostrando nuevamente el mensaje de invitacion
return letra; 
}



int verify_dni (char *cadena) { //FUNCION VERIFY
int longitud;
int i;

longitud = strlen(cadena);
if (longitud == 9) { //COMPRUEBA SI LA LONGITUD DEL DNI ES 9
return 1;
}

else {
return 0;
}

for (i = 0; i <= 7; i++) {
if (cadena[i] >= '0' && cadena[i] <= '9') { //COMPRUEBA SI LOS 8 PRIMEROS CARÁCTERES SON NUMEROS
return 1;
}
else {
return 0;
}

for (i = 8; i < 9; i++) {

if (cadena[i] >= 'A' && cadena[i] <= 'Z') { //COMPRUEBA SI EL ÚLTIMO CARÁCTER ES UNA LETRA
return 1;
}
else {
return 0;
}
}
}
}


void display_patient (struct unPaciente *tabla ,int numero) { //el numero pasado a la funcion va a indicar la informacion de que paciente se desea mostrar (indice)

fprintf (stdout, "> %s ; %s ; %d ; %d ; %d ; %c \n" ,tabla[numero].nombre ,tabla[numero].dni ,tabla[numero].edad ,tabla[numero].tos ,tabla[numero].fiebre ,tabla[numero].sintomas);

return;
}





get_caracter (char mensaje, char *comprobacion) {
char letra;
char extra[256]; //cadena extra para comprobar si se introducen algo más que el número
char i;
int longitud, valores;
mensaje = (char *) malloc (256*sizeof(char));


do {
    fprintf (stdout, "%s" ,mensaje); //Se imprime el mensaje de invitacion al usuario recibida como parametro
    fprintf (stdout ,"%s" ,comprobacion); //Se imprime la cadena de comprobacion recibida como parametro
    fscanf (stdin, "%c" ,&letra); //Se escanea el input del usuario
    valores = sscanf (letra ,"%c %s" ,&letra ,extra); //Se le asigna a valores un numero en funcion del numero de elementos introducidos, si es distinto de 1, dará error
} while (valores != 1);

longitud = strlen(comprobacion);
comprobacion = (char *) malloc (longitud*sizeof(char));

for (i = 0; i <= longitud; i++) {
if (letra = comprobacion[i]) { //Se revisan todos los elementos de la cadena de comprobacion, si hay un elemento que coincida, se devuelve esa letra
return letra;
}
else {
fprintf (stdout ,"%s" ,comprobacion);
continue;
}
}
}

And inout.h, with the prototypes for the functions in inout.c

#ifndef INOUT_H
#define INOUT_H


//DECLARACIONES DE LAS FUNCIONES fuera del menú

struct unPaciente {
    char nombre[25];
    char dni[10];
    unsigned short edad;
    int fiebre;
    int tos;
    char sintomas;
}losPacientes[100];


void stripe (char caracter, int numchar);

void headline (char * APLICACION ,char caracterhl, int numchar);     // Funcion headline. Imprime una cadena centrada, entre 2 caracteres dados por el usuario.

int yes_or_no (); 

void get_string(char *mensaje,int min, int max, char*la_cadena); 

int get_integer (char *mensaje, int min, int max); 

char get_character (char *mensaje, char *comprobacion); 

void display_patient (struct unPaciente *tabla,int numero);

#endif

Each .h starts and ends with #ifndef and #endif, and database.c is reading these files and I assume that their prototypes conflict with the prototypes within database.c, but I dont know why. I was told that removing the multiple copies of ´´´struct unPaciente´´´ that I had in each header would solve the issue, but Im still getting the same result.

2 Answers

This seemingly paradoxical error message ...

database.c:21:5: error: conflicting types for ‘p_register’
   21 | int p_register (struct unPaciente *tabla, int *numero) {
      |     ^~~~~~~~~~
In file included from database.c:11:
database.h:20:5: note: previous declaration of ‘p_register’ was here
   20 | int p_register (struct unPaciente *tabla, int *numero);

... is trying to tell you that the struct unPaciente in one of those declarations is a different type than the one in the other declaration.

Why? Because database.h does not itself #include header inout.h, where the structure definition resides, and because database.c includes database.h before inout.h, so that the former does not see a declaration of the structure from the latter, either. Under these circumstances, the declaration of struct unPaciente *tabla inside the function prototype provides an implicit declaration of struct unPaciente as an incomplete structure type, and that implicit declaration is scoped to the prototype, so that it is disassociated from the later file-scope declaration brought in from inout.h.

The best thing to do is to have database.h include inout.h itself. More generally, each source file, including headers, should include all headers needed to provide datatypes and functions referenced within. With proper use of inclusion guards in each header, as you appear to have, there is no issue with this producing multiple inclusions of the same headers, and it gets you order-independence for your header inclusions.

The problem is the inclusion order in your database.c file.

You first include database.h which declares the p_register function:

int p_register (struct unPaciente *tabla, int *numero); 

But notice, that struct unPaciente hasn't been declared yet. The compile will warn you about this with:

database.h:8:28: warning: ‘struct unPaciente’ declared inside parameter list will not be visible outside of this definition or declaration

Then you proceed to include inout.h which formally declares struct unPaciente. But now when you come to defining p_register the two struct unPaciente are different. One has been declared implicitly during the declaration, the other one comes from the inout.h. Because they are not the same, the compiler will complain.

Solution

What you should do is move the

#include "inout.h"

from database.c to database.h This way the pre-processor will include it before the declaration and the compiler will have the same struct unPaciente during both the declaration and during the definition.

Related