Ссылка на неопределенную функцию в C - PullRequest
1 голос
/ 11 июля 2020

У меня есть несколько файлов с основными функциями в C, например, есть файлы с именем show. c, delete. c доп. c (...). У меня также есть файл с именем интерпретатор. c, который может вызывать один из файлов, например delete. c. Большинство этих файлов реализуют основную функцию, такую ​​как 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);
}

Интерпретатор:

#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;
}

Я пытался исследовать для подобных проблем, и я нашел несколько небольших возможных решений, но не могу решить свою проблему, как показано внизу G CC ошибка компиляции

1 Ответ

2 голосов
/ 11 июля 2020

Вы не "вызываете исходные файлы"; исходные файлы определяют функции и переменные, и при компиляции те, которые определены в разных файлах, могут использовать друг друга, если у них есть объявление (обычно в файле заголовка) или указатель (через методы динамической c ссылки, такие как POSIX dlsym () ).

Рассмотрим этот минимальный пример. Во-первых, пример . 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;
}

и помощник. c:

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

Вы компилируете каждый исходный файл в объектный файл:

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

, а затем вы связываете их с исполняемой программой:

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

, которую вы можете запустить, используя

./program

Обычно каждый C исходный файл, который предоставляет функции или переменные, которые можно использовать вне этого файла, объявляет их в файле заголовка. Вот лучший пример.

градусы.h

#ifndef   DEGREES_H
#define   DEGREES_H

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

#endif /* DEGREES_H */

#ifndef, #define и #endif используются в качестве защиты, так что если вы #include файл более одного раза, функции объявляются только один раз. (Компилятор пожалуется, если увидит несколько объявлений. Кроме того, нам не нужно использовать здесь extern.)

Реализация вышеизложенного будет в градусах. 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;
}

В программе myprog. c в том же проекте вы должны использовать приведенное выше, таким образом:

#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;
}

и снова вы ' d сначала скомпилируйте два исходных файла в объектные файлы,

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

, а затем скомпилируйте их вместе с программой, например, myprog ,

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

, которую затем можно запустить:

./myprog

Также возможно скомпилировать и связать функции и переменные, объявленные в градусов.h , с библиотекой stati c (libdegrees.a) или динамической c (libdegrees.so), и установите файл заголовка в стандартное расположение, чтобы ваша программа могла вместо этого использовать #include <degrees.h> и ссылку программы на библиотеку через -ldegrees, но это лучше оставить, пока вы не освоитесь с несколькими файлами.

До тех пор вы можете найти следующий Makefile полезный

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 $@

Вы можете добавить несколько программ в строку PROGS, разделив их пробелами, и скопировать myprog: строки для каждого, перечисляя объектные файлы, которые нужны программе.

При этом все, что вам нужно для компиляции программы, - это набрать make.

Этот форум ест вкладки, а в Makefiles требуется отступ использовать тех. Итак, если вы просто скопируете это в файл, это не сработает. Однако вы можете исправить это, запустив

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

, который удаляет все начальные пробелы в каждой строке с вкладкой в ​​файле Makefile.

Если вы используете отдельные библиотеки, обычно libm ( #include <math.h>), вам просто нужно добавить -lm (da sh ell em) в строку LDFLAGS. Если вы в конечном итоге поиграете с динамическими c линковками, это -ldl.

Если бы вы написали графическую программу с помощью Gtk +, вы бы добавили `pkg-config --cflags gtk+-3.0` (включая обратные кавычки) к CFLAGS строка и `pkg-config --libs gtk+-3.0` для строки LDFLAGS и #include <gtk/gtk.h> для вашей программы.

...