2015-06-07 2 views
2

У меня возникла проблема при компиляции моего кода. Я не получаю сообщений об ошибках. Тем не менее, я получаю следующее сообщение:C: команда компоновщика не удалась с кодом выхода 1

Undefined symbols for architecture x86_64: 
    "_lookup", referenced from: 
     _main in sixteen2-85c27c.o 
ld: symbol(s) not found for architecture x86_64 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 

Я никогда не сталкивался ничего подобного, и большая часть информации я могу найти в Интернете включает в себя Objective-C, не ясно, C. Я был бы признателен за любую помощь.

Вот мой код:

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

int main (int argc, char *argv[]) { 
    struct entry { 
     char word[15]; 
     char definition[100]; 
    }; 

    const struct entry dictionary[100] = 
    {{"aardvark", "a burrowing African mammal"}, 
    {"abyss", "a bottomless pit"}, 
    {"acumen", "mentally sharp; keen"}, 
    {"addle", "to become confused"}, 
    {"aerie", "a high nest"}, 
    {"affix", "to append; attach"}, 
    {"agar", "a jelly made from seaweed"}, 
    {"ahoy", "a nautical call of greeting"}, 
    {"aigrette", "an ornamental cluster of feathers"}, 
    {"ajar", "partially opened"}}; 

    int entries = 10; 
    int entryNumber; 
    int lookup (const struct entry dictionary[], const char search[], const int entries); 

    if (argc != 2) 
    { 
     fprintf (stderr, "No word typed on the command line.\n"); 
     return EXIT_FAILURE; 
    } 

    entryNumber = lookup (dictionary, argv[1], entries); 

    if (entryNumber != -1) 
     printf("%s\n", dictionary[entryNumber].definition); 
    else 
     printf("Sorry, %s is not in my dictionary.\n", argv[1]); 

    return EXIT_SUCCESS; 
} 
+5

Где функция 'lookup' определена? –

ответ

10

Вы имеете следующую строку кода:

int lookup (const struct entry dictionary[], const char search[], const int entries); 

Внутри главной функции. С этим связаны две основные проблемы.

  1. Объявление функций не может появляться внутри другой функции. Линия я цитировал потребности появляться за пределами вашей основной функции следующим образом:

    int lookup(.....) 
    //code here 
    int main(...) 
    { 
        //more code here 
    } 
    
  2. Даже если вы объявляете функцию «подстановки», вы никогда не определить его. Вероятно, это вызывает ошибку компоновщика. Компилятор компилирует все функции, а затем компоновщик идет, чтобы связать функции вместе (так сказать) и обнаруживает, что, хотя функция «lookup» объявлена ​​и затем вызывается, она на самом деле нигде не существует! (насколько мне известно, функция «lookup» не существует в stdlib.h или stdio.h). Это не позволяет компоновщику выполнять свою работу.

Повторим, ваш код должен быть преобразован следующим образом:

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

int lookup (const struct entry dictionary[], const char search[], const int entries) 
{ 
    //lots of code belongs in here, but that's for you to figure out :) 
} 

int main (int argc, char *argv[]) { 
    struct entry { 
     char word[15]; 
     char definition[100]; 
    }; 

    const struct entry dictionary[100] = 
    {{"aardvark", "a burrowing African mammal"}, 
    {"abyss", "a bottomless pit"}, 
    {"acumen", "mentally sharp; keen"}, 
    {"addle", "to become confused"}, 
    {"aerie", "a high nest"}, 
    {"affix", "to append; attach"}, 
    {"agar", "a jelly made from seaweed"}, 
    {"ahoy", "a nautical call of greeting"}, 
    {"aigrette", "an ornamental cluster of feathers"}, 
    {"ajar", "partially opened"}}; 

    int entries = 10; 
    int entryNumber; 
    //**REMOVE THIS LINE** Move it up top.... 
    //int lookup (const struct entry dictionary[], const char search[], const int entries); 

    if (argc != 2) 
    { 
     fprintf (stderr, "No word typed on the command line.\n"); 
     return EXIT_FAILURE; 
    } 

    entryNumber = lookup (dictionary, argv[1], entries); 

    if (entryNumber != -1) 
     printf("%s\n", dictionary[entryNumber].definition); 
    else 
     printf("Sorry, %s is not in my dictionary.\n", argv[1]); 

    return EXIT_SUCCESS; 
} 

Я надеюсь, что это помогает. Если вы не понимаете, что делает «компоновщик» или почему это важно, оставьте комментарий, и я соответствующим образом отредактирую ответ. Понимание компоновщиков и компиляторов является одним из многих факторов, отделяющих посредственных программистов от программистов C!


Я думаю, было бы полезно на данном этапе объяснить, что такое компоновщик. Прежде чем мы дойдем до этого, важно понять, что делает ваш компилятор и что такое компилированная программа.

Основываясь на коде, опубликованном в вашем вопросе, я думаю, что можно с уверенностью предположить, что вы использовали компилятор более одного раза :). Я скажу несколько вещей, которые вы уже знаете, но держитесь со мной. Файлы «.c» и «.h» описывают алгоритмы. Эти файлы легки для людей, чтобы читать и редактировать, однако на вашем компьютере может быть трудно извлечь из них смысл. Чтобы ваш компьютер «запускал» программу в этих файлах, алгоритмы должны быть преобразованы в язык, который понимает ваш компьютер. Этот язык, называемый «машинный язык», трудно для людей писать, поэтому мы пишем на C или C++ и конвертируем наши программы на C и C++ в «машинный язык» с использованием компилятора.

Теперь функция компоновщика здесь тонкая, но очень важная. Для новичка легко подумать, что компоновщик совершенно не нужен: если компилятор преобразует C в «машинный язык», то задание закончено? ну ... не совсем.

Понимаете, каждый бит «машинного языка» в вашей скомпилированной программе имеет адрес памяти.Рассмотрим следующий пример игрушечный:

#include <stdio.h> 

int addnums(int numbers[], int length) 
{ 
    int total = 0; 
    for(int i = 0; i < length; i++) 
    { 
     total += numbers[i]; 
    } 

    return total; 
} 

int main(int argc, char** argv) 
{ 
    int mynums[] = {1, 2, 3, 4, 5}; 
    int total = addnums(mynums, 5); 
    printf("the total of the array is %i\n", total); 
    return 0; 
} 

Если бы мы должны были смотреть на машинном коде для этой игрушечной программы, мы увидим, что каждая функция имеет начальную точку и конечную точку в памяти вашего компьютера. Это означает, что каждая функция имеет адрес, где он начинается. Когда ваш компьютер выполняет линию

int total = addnums(mynums, 5); 

Он должен «прыгать» в другую часть машинного кода. «int main()» может начинаться с адреса 100, а «int addnums()» - по адресу 50. Компьютер должен выполнить машинный код по адресу 50, когда он достигнет этой строки.

Компилятор не относится к адресам функций. Он просто компилирует код и оставляет его в другой программе, чтобы поместить правильные адреса в машинный код. Если компоновщик говорит что-то вроде

symbol(s) not found 

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

int total = addnums(mynums, 5); 

и сказать: «Да ??? куда я иду ??» Без адреса для перехода к функции «int addnums()» ваш процессор будет полностью потерян.

и ваша программа будет таинственно сбой.

Линкера избавляет вас от этой боли, отбрасывая ошибку и останавливая процесс компиляции. В мои любительские дни программирования встроенных систем у меня была эта проблема несколько раз, и это был кошмар для отладки.

Надеюсь, это поможет. Скажи мне, плохо ли мое объяснение.

+0

Нет, я не знаю, что такое компоновщик. Благодарю. –

+3

Я отредактирую свой комментарий, чтобы объяснить, что такое компоновщик. Надеюсь, это имеет смысл :) –

Смежные вопросы