多个文件之间的函数类型冲突

标签 c

我的代码中的每个函数都出现错误,内容如下:

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);

我有一个名为database.c的文件,它需要从其他文件中获取其他函数的原型(prototype),这些文件称为database.h和inout.h。 每个文件的代码如下:

数据库.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;
}

数据库.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(其中包含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;
}
}
}

还有 inout.h,以及 inout.c 中函数的原型(prototype)

#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

每个.h都以#ifndef和#endif开始和结束,database.c正在读取这些文件,我假设它们的原型(prototype)与database.c中的原型(prototype)冲突,但我不知道为什么。有人告诉我,删除每个 header 中的“struct unPaciente”的多个副本可以解决问题,但我仍然得到相同的结果。

最佳答案

这个看似矛盾的错误消息......

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);

...试图告诉您其中一个声明中的 struct unPaciente 与另一个声明中的类型不同。

为什么?因为 database.h 本身并不包含结构定义所在的 #include 头文件 inout.h,并且因为 database.cinout.h 之前包含 database.h,因此前者也看不到后者的结构声明。在这种情况下,函数原型(prototype)内的 struct unPaciente *tabla 声明提供了 struct unPaciente 的隐式声明作为不完整的结构类型,并且该隐式声明是作用域为原型(prototype),以便它与后面从 inout.h 引入的文件作用域声明解除关联。

最好的办法是让 database.h 包含 inout.h 本身。更一般地说,每个源文件(包括 header )应包含提供其中引用的数据类型和函数所需的所有 header 。通过在每个 header 中正确使用包含防护,正如您所看到的,这不会产生相同 header 的多个包含项,并且它可以使您的 header 包含项与顺序无关。

关于多个文件之间的函数类型冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65654838/

相关文章:

c - 这段代码是否尽可能高效?

c - 如何检查字符串是否包含特定字符?

c - 初始化结构数组

javascript - 如何添加允许在 Umbraco 中添加新行的验证

c - 为什么我的所选元素的清除功能无法正常工作?

c - a+i 和 a[i] 有什么区别

c - 从文件中读取内容

c - 如何计算 mst 图的成本。

c - 传递指针或 const 结构是否有速度差异

c - 必须包含\n Xcode C