简体   繁体   中英

Undefined function reference in C

I've several files with main functions in C, for example, I've files called show.c , delete.c add.c (...). I also have a file, called interpreter.c , which may call one of the files, for example delete.c . Most of these file implement a main function, like the delete.c :

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>

int main (int argc, char *argv[]) 
{
    int fd, rm;
    char *caminho = argv[1]; // argumento inserido no terminal
    char caminhod[30]="../TPSOFinal/";

    strcat(caminhod,argv[1]);
    
    fd = open(caminhod, O_RDONLY);

    rm=unlink(caminhod);

    // Verifica se o caminho inserido no input existe
    if(rm == 0){
        write(1,"Ficheiro eliminado!!!\n", 22);
        return 0;
    }
    else{
        write(1,"Erro ao eliminar ficheiro !!!\n", 29);
        perror("Erro");
    }
    
    return 0;
    close(fd);
}

The interpreter:

#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <readline/readline.h>
#include <readline/history.h>


#define LER_BUFFER 1024
#define TBUFF 64
#define DELIM "\t\r\n\a"

int mostra(char **args);
int conta(char **args);
int acrescenta(char **args);
int apaga(char **args);
int informa(char **args);
int lista(char **args);
int manual(char **args);
int termina(char **args);


char *comando[] =
{
    "mostra <caminho>",
    "conta  <caminho>",
    "acrescenta <caminho> <caminho destino>",
    "apaga <caminho>",
    "informa <caminho>",
    "lista <caminho>",
    "manual",
    "termina",
    " ",
};


int (*fcomandos[]) (char**) =
{
    &mostra,
    &conta,
    &acrescenta,
    &apaga,
    &informa,
    &lista,
    &manual,
    &termina
};
    
int ncomandos()
{
    return sizeof(comando)/sizeof(char*);
}


void processa(char *linha, char **argv)
{
    while(*linha != '\0')
    {
        while(*linha == ' ' || *linha == '\t' || *linha == '\n')
        {
            *linha++ = '\0';      //troca caracteres especiais
        }
        *argv++ = linha;              //guarda posição

        while (*linha != '\0' && *linha != ' ' && *linha != '\t' && *linha != '\n')
        {
            linha++;
        }
    }
    *argv = NULL;
}
char *lerlinha (void)
{
    char *linha = NULL;
    ssize_t tam = 0;
    getline (&linha, &tam, stdin);

    return linha;
}

char **separa (char *linha)
{
    int tam = TBUFF, pos = 0;
    char **palavras = malloc (tam *sizeof(char*));
    char *palavra;

    if (!palavras)
    {
        perror("Erro");
        exit(EXIT_FAILURE);
    }
    
    palavra = strtok (linha, DELIM);

    while (palavra != NULL)
    {
        palavras [pos] = palavra;
        pos ++;
        
        if (pos >= tam)
        {
            perror ("Erro");
        }
        
    }
    palavra = strtok(NULL, DELIM);
    
    palavras [pos] = NULL;
    return palavras;
}

int launch (char **args)
{
    pid_t pid, wpid;
    int estado;

    pid = fork();
    
    if (pid == 0)
    {
        if(execvp(args[0],args)==-1){ perror ("Erro!"); }
        
        exit (EXIT_FAILURE);
    }

    if (pid <0)
    {
        perror ("Erro!");
    }
    else
    {
        do{wpid = waitpid(pid, &estado, WUNTRACED);}
        while (!WIFEXITED(estado)&& !WIFSIGNALED(estado));
    }

    return 1;

    
}
//Testa se os comandos existem
int mostra (char **args)
{
    if (args[1] == NULL)
    {
        perror("sem argumentos ");
    }
    else if (chdir (args[1]) != 0)
    {
        perror ("Erro!");
    }
    return 1;
}

int conta ( char ** args)
{
    if (args[1] == NULL)
    {
        perror("Sem argumentos "); 
    }
    else if (chdir (args[1])!= 0)
    {
        perror ("Erro!");
    }
    return 1;
}

// Manual dos comandos
int manual (char **args)
{
    int i;
    printf("\n\nMiguel Oliveira\n");
    printf("10260 - LESI\n");
    printf("Sistemas Operativos e Sistemas Distribuidos\n");
    printf("\nLista de Comandos\n");

    for (i=0; i<ncomandos(); i++)
    {
        printf("%s\n", comando[i]);
    }
    return 1;
}

int termina (char **args)
{
    return 0;
}


//Executa os comandos
int executar (char **args)
{
    int i;
    
    if (args[0] == NULL)
    {
        return 1;
    }

    for (i=0; i<ncomandos(); i++)
    {
        if (strcmp(args[0], comando[i])==0)
        {
            return (*fcomandos[i])(args);
        }
    }
    return launch(args);
}

//Interpretador
void  interpretador (void)
{
    char  *linha;             
    char  **args;
    int estado;            

    do
    {                   
        printf("%% "); 
        linha = lerlinha();
        args = separa(linha);
        estado = executar(args);

        free(linha);
        free(args);  
        
    } while (estado);
}

int main (void)
{
    interpretador();

    return EXIT_SUCCESS;
}

I've tried to research for similar problems, and i've found some little possible solutions, but cannot solve my problem, as show on bottom GCC compile mistake

You do not "call source files"; source files define functions and variables, and when compiled, ones defined in different files can use each other if they have a declaration (in a header file, usually) or a pointer (via dynamic link methods, like POSIX dlsym()).

Consider this minimal example. First, example.c :

#include <stdlib.h>
#include <stdio.h>

/* We expect someone else to define these */
extern int one(void);

int main(void)
{
    printf("one() returned %d.\n", one());
    return EXIT_SUCCESS;
}

and helper.c :

int one(void)
{
    return 2;  /* TODO: It's not one! */
}

You compile each source file to an object file:

gcc -Wall -O2 -c example.c
gcc -Wall -O2 -c helper.c

and then you link them to an executable program:

gcc -Wall -O2 example.o helper.o -o program

which you can run using

./program

Normally, each C source file that provides functions or variables usable outside that file, declares them in a header file. Here's a better example.

degrees.h

#ifndef   DEGREES_H
#define   DEGREES_H

double radians_to_degrees(double);
double degrees_to_radians(double);

#endif /* DEGREES_H */

The #ifndef , #define , and #endif are used as guards, so that if you #include the file more than once, the functions get declared only once. (The compiler will complain if it sees multiple declarations. Plus, we don't need to use extern here.)

The implementation of the above is then in degrees.c ,

#ifndef  PI
#define  PI  3.14159265358979323846
#endif

double  degrees_to_radians(double degrees)
{
    return degrees * PI / 180.0;
}

double  radians_to_degrees(double radians)
{
    return radians * 180.0 / PI;
}

In a program myprog.c in the same project, you would use the above thus:

#include <stdlib.h>
#include <stdio.h>
#include "degrees.h"

int main(void)
{
    printf("45 degrees is %.6f radians.\n", degrees_to_radians(45.0));
    printf("2 radians is %.3f degrees.\n", radians_to_degrees(2.0));
    return EXIT_SUCCESS;
}

and again you'd compile first the two source files to object files,

gcc -Wall -O2 -c degrees.c
gcc -Wall -O2 -c myprog.c

and then link together to a program, say myprog ,

gcc -Wall -O2 degrees.o myprog.o -o myprog

which you can then run:

./myprog

It is also possible to compile and link the functions and variables declared in degrees.h to a static ( libdegrees.a ) or a dynamic ( libdegrees.so ) library, and install the header file to the standard location, so that your program could instead use #include <degrees.h> and the program link to the library via -ldegrees , but that is better left until you are well comfortable working with multiple files.

Until then, you might find the following Makefile useful

CC      := gcc
CFLAGS  := -Wall -O2
LDFLAGS :=
PROGS   := myprog

all: clean $(PROGS)

clean:
    rm -f *.o $(PROGS)

%.o: %.c
    $(CC) $(CFLAGS) -c $^

myprog: degrees.o myprog.o
    $(CC) $(CFLAGS) $^ -o $@

You can add multiple programs in the PROGS line, separated by spaces, and copy the myprog: lines for each, listing the object files that program needs.

With this, all you need to compile the program is to type make .

This forum eats Tabs, and Makefiles need indentation to use those. So, if you just copy-paste that to a file, it won't work. You can fix it, though, by running

sed -e 's|^  *|\t|' -i Makefile

which removes all initial spaces on each line with a tab in file Makefile.

If you use separate libraries, typically libm ( #include <math.h> ), you just need to add -lm (dash ell em) to the LDFLAGS line. If you eventually play with dynamic linking, that's -ldl .

If you were to write a graphical program using Gtk+, you'd append ` pkg-config --cflags gtk+-3.0 ` (including the backticks `) to the CFLAGS line, and ` pkg-config --libs gtk+-3.0 ` to the LDFLAGS line, and #include <gtk/gtk.h> to your program.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM