clang: ошибка: команда компоновщика завершилась неудачно с кодом выхода 1 с повторяющимся символом _TableLookup в database.o и main.o

#c #xcode #data-structures #struct

#c #xcode #структуры данных #структура

Вопрос:

После изменения кода я получил новую ошибку в database_definitions.файл заголовка h. Ошибка находится рядом с ‘extern const Lookup_Table TableLookup[TABLE_COUNT];’ и упоминается ошибка в коде с комментариями рядом с ней. Я также получил предупреждение в файле ‘database.c’ рядом с возвратом amp; (TableLookup[index]); в функции ‘Lookup_Table * GetTableMetadata (char * tableName)’. Ошибка вставляется в код рядом с ней. Пожалуйста, просмотрите и помогите мне в решении этой проблемы.

 **database.c**:
    const Lookup_Table TableLookup[TABLE_COUNT]=
{
    {
        .tableName          = "Folder_Table",
        //        .tableInitializer   = (void*)amp;InitFolder_Table,
        .tableMemory        = sizeof(Folder_Table),
        .columns            = 5,
        .columnNames        = {"folderID","field1","field2","field3","field4"},     // Fill out field name metadata
        .columnSize         = {SIZE_OF(Folder_Table,folderID), SIZE_OF(Folder_Table,field1), SIZE_OF(Folder_Table,field2),
            SIZE_OF(Folder_Table,field3),   SIZE_OF(Folder_Table,field4)},
        .columnType         = {TYPE_INT, TYPE_FLOAT, TYPE_INT, TYPE_FLOAT, TYPE_TEXT},
        .subTable           = {{.tableName = "Item_Table", .pointerOffset = offsetof(Folder_Table,item)},
            {.tableName = "nextRow", .pointerOffset = offsetof(Folder_Table, nextRow)},
            {.tableName = "lastRow", .pointerOffset = offsetof(Folder_Table, lastRow)},
            {.tableName = "",         .pointerOffset = 0 }},
    },
    {
        .tableName          = "Item_Table",
        //        .tableInitializer   = (void*)amp;InitItem_Table,
        .tableMemory        = sizeof(Item_Table),
        .columns            = 4,
        .columnNames        = {"ItemID","FolderID","field1","field2"},
        .columnSize         = {SIZE_OF(Item_Table,itemID), SIZE_OF(Item_Table,folderID), SIZE_OF(Item_Table,field1),
            SIZE_OF(Item_Table,field2)},
        .columnType         = {TYPE_INT, TYPE_INT, TYPE_TEXT, TYPE_FLOAT},
        .subTable           = {{.tableName = "nextRow", .pointerOffset = offsetof(Item_Table, nextRow)},
            {.tableName = "lastRow", .pointerOffset = offsetof(Item_Table, lastRow)},
            {.tableName = "", .pointerOffset = 0}},
    }
};


//====================================================================================
// Struct Table Initializer and metadata functions
//====================================================================================
//------------------------------------------------------------------------------------
// Find the memory size of a table specified by name
//------------------------------------------------------------------------------------
int GetTableSize(char *tableName)
{
    int index;

    //// Find function matching function name string
    for (index=0 ; index < TABLE_COUNT; index  )
    {
        if (strcmp(TableLookup[index].tableName, tableName))
        {
            return(TableLookup[index].tableMemory);
        }
    }
    return 1;  // Return error, should this be an exception?
}

//------------------------------------------------------------------------------------
// Return the index of of the table from the table-lookuptable
//------------------------------------------------------------------------------------
Lookup_Table* GetTableMetadata(char *tableName)
{
    //// Find function matching function name string
    for (int index=0; index < TABLE_COUNT; index  )
    {
        if (strcmp(TableLookup[index].tableName, tableName))
        {
            `return amp;(TableLookup[index]);//error: 'Returning 'const Lookup_Table*(aka    'const structLookup_Table') from a function with result type 'Lookup_Table'(aka 'struct   Lookup_Table") discards qualifiers`'
        }
    }
    return 0;  // Return error
}

**database.h**:
#ifndef database_h
#define database_h

#include "database_definitions.h"

#define ONE_ROW 1

//====================================================================================
// Function Definitions 
//====================================================================================
int SQLOpen(void);
//isc_db_handle SQLGetDatabase(void);
Lookup_Table* GetTableMetadata(char *tableName);
Sub_Table* GetSubTableMetadata(char *tableName, char *subTableName);

#endif

    **database_definitions.h**:





#ifndef database_database_h
    #define database_database_h
    extern const Lookup_Table TableLookup [TABLE_COUNT]; 
//error:unknown type name 'Lookup_Table'
//====================================================================================
// SQL Table Metadata Structures
//====================================================================================
typedef struct Folder_Table                         // Table type name gets "_Table" added to the SQLite name
{
    //// Fields                                     // Comments are added to seperate the fields, Relationships, and metadata
    int     folderID;                               // Fields are added as elements of the type and length listed in SQLite
    float   field1;
    int     field2;
    float   field3;
    char    field4[40];                             // string length '40' is queried from SQLite settings for field

    //// Relationships
    struct Item_Table       *item;                  // Pointer to the sub-table
    struct Folder_Table     *nextRow;               // Linked List Pointer to the next-row
    struct Folder_Table     *lastRow;               // Linked List Pointer to the last-row

} Folder_Table;


typedef struct Item_Table
{
    //// Fields
    int     itemID;
    int     folderID;
    char    field1[32];
    float   field2;

    //// Relationships
    Folder_Table            *folder;
    struct Item_Table       *nextRow;
    struct Item_Table       *lastRow;

} Item_Table;
typedef struct Sub_Table
{
    char    tableName      [TABLE_NAME_LENGTH];                 // Sub-table name
    int     pointerOffset;                                      // Sub-table pointer memory offset in the struct
}Sub_Table;

typedef struct Lookup_Table
{
    char        tableName  [TABLE_NAME_LENGTH];                 // Stores table name
    void        (*tableInitializer)(void *);                    // Pointer to the initializer function
    int         tableMemory;                                    // Size of the table memory instance
    int         columns;                                        // Number of columns in the table
    char        columnNames[MAX_COLUMNS][COLUMN_NAME_LENGTH];   // Array of column names
    int         columnSize [MAX_COLUMNS];                       // Array of column variable memory sizes
    int         columnType [MAX_COLUMNS];                       // Array of column variable types
    Sub_Table   subTable   [MAX_SUB_TABLES];                    // Stores sub-table pointers
}Lookup_Table;




#endif

**main.c**:
#include <stdio.h>
#include "database.h"


int main(int argc, const char * argv[])
{

   // SQLOpen();

    return 0;
}
  

Комментарии:

1. Похоже на TableLookup в database_definitions. h определяется (через включение) как в database.c, так и в main.c. Скомпилированный объектный файл для database.c и main.c содержит его копию, поэтому компоновщик видит повторяющиеся определения и жалуется. Можете ли вы определить таблицу в database.c?

2. const Lookup_Table TableLookup[TABLE_COUNT]={...} не принадлежит вашему заголовочному файлу. Он должен быть extern const Lookup_Table TableLookup[TABLE_COUNT]; в заголовке и определен в одном исходном файле или static в заголовке, который, хотя и дублируется на единицу перевода, все равно будет работать для ваших нужд.

3. @BrianWalker У меня есть другие функции в дальнейшем, которые будут связаны с TableLookup, и мне нужно определить в database_definitions. файл заголовка h. Есть ли другой способ избавиться от этой проблемы?

4. @WhozCraig Спасибо за ответ. Я не понял, что вы говорили. Где я должен изменить имя на extern const Lookup_Table TableLookup?

5. Удалите весь блок кода TableLookup в database_definitions. h и поместите его в базу данных.c. В database_definitions.h добавьте «extern const Lookup_Table TableLookup[TABLE_COUNT];». Это позволит другим файлам видеть TableLookup, но определять фактические данные для TableLookup только один раз.

Ответ №1:

Вы определяете TableLookup в своем заголовочном файле, который вы включаете из нескольких исходных (и, следовательно, объектных) файлов. Это приводит к тому, что он определяется во всех объектных файлах, которые включают этот заголовок, и это приводит к тому, что компоновщик выдает эти ошибки.

Что вам нужно сделать, это объявить TableLookup as extern , а затем определить его в database.c (или в каком-либо другом файле, где он подходит). Итак, в database_definitions.h :

 extern const Lookup_Table TableLookup[ TABLE_COUNT ];
  

И в database.c :

 #include "database_definitions.h"

/* ... */

const Lookup_Table TableLookup[TABLE_COUNT]=
{
    {
        .tableName          = "Folder_Table",
//        .tableInitializer   = (void*)amp;InitFolder_Table,
        .tableMemory        = sizeof(Folder_Table),
        .columns            = 5,
        .columnNames        = {"folderID","field1","field2","field3","field4"},     // Fill out field name metadata
        .columnSize         = {SIZE_OF(Folder_Table,folderID), SIZE_OF(Folder_Table,field1), SIZE_OF(Folder_Table,field2),
                               SIZE_OF(Folder_Table,field3),   SIZE_OF(Folder_Table,field4)},
        .columnType         = {TYPE_INT, TYPE_FLOAT, TYPE_INT, TYPE_FLOAT, TYPE_TEXT},
        .subTable           = {{.tableName = "Item_Table", .pointerOffset = offsetof(Folder_Table,item)},
                               {.tableName = "nextRow", .pointerOffset = offsetof(Folder_Table, nextRow)},
                               {.tableName = "lastRow", .pointerOffset = offsetof(Folder_Table, lastRow)},
                               {.tableName = "",         .pointerOffset = 0 }},
    },
    {
        .tableName          = "Item_Table",
//        .tableInitializer   = (void*)amp;InitItem_Table,
        .tableMemory        = sizeof(Item_Table),
        .columns            = 4,
        .columnNames        = {"ItemID","FolderID","field1","field2"},
        .columnSize         = {SIZE_OF(Item_Table,itemID), SIZE_OF(Item_Table,folderID), SIZE_OF(Item_Table,field1),
                               SIZE_OF(Item_Table,field2)},
        .columnType         = {TYPE_INT, TYPE_INT, TYPE_TEXT, TYPE_FLOAT},
        .subTable           = {{.tableName = "nextRow", .pointerOffset = offsetof(Item_Table, nextRow)},
                               {.tableName = "lastRow", .pointerOffset = offsetof(Item_Table, lastRow)},
                               {.tableName = "", .pointerOffset = 0}},
    }
};
  

Это позволяет всем исходным файлам, в которые вы включаете database_definitions.h , знать, что переменная существует, но они не содержат явных определений. Вместо этого компоновщику поручено «связать» эти ссылки на внешние символы с местами, где определены символы.

Комментарии:

1. Спасибо за ответ. Я обновил свой код. Я получил новую ошибку и упомянул в приведенном выше коде. Пожалуйста, просмотрите его. ошибка: неизвестное имя типа ‘Lookup_Table’ и одно предупреждение в файле database.c.

2. В database_definitions.h , переместите extern const... в конец файла, чтобы он понимал тип Lookup_table . Что касается другой ошибки в database.c , это потому, что вы определили таблицу поиска как const , но вы возвращаете не const указатель из функции. Измените возвращаемый тип GetTableMetadata to const Lookup_Table* .

3. Вы просите меня заменить ‘Lookup_Table* GetTableMetadata (char tableName’ на ‘const Lookup_Table GetTableMetadata (char * tableName)’?? когда я это сделал, я получил ошибку: конфликтующие типы для ‘GetTableMetadata’

4. Чтобы изменить сигнатуру функции, вам необходимо изменить ее как в файлах .h, так и .c . Прежде чем вы в следующий раз спросите о StackOverflow, я советую вам глубже понять основы, например, пройдя руководство для начинающих по C.

Ответ №2:

TableLookup является массивом и не должен определяться в .h .

Вот что произошло:

два файла, включающие database_definitions.h — database.c и main.c, имеют определение массива в соответствующих объектных файлах — database.o и main.c.o Когда компоновщик пытается объединить два файла, он терпит неудачу, потому что TableLookup определяется дважды.

TableLookup должен быть определен в одном из файлов .c — предпочтительно database.c, затем любой файл .c, который хочет его использовать, должен добавить:

 extern const Lookup_Table TableLookup[TABLE_COUNT];
  

или, что еще лучше, добавьте extern в database.h, и любой .c, который включает его, будет иметь extern и сможет его использовать

Комментарии:

1. Спасибо за ответ. Я обновил свой код. Я получил новую ошибку и упомянул в приведенном выше коде. Пожалуйста, просмотрите его. ошибка: неизвестное имя типа ‘Lookup_Table’ и одно предупреждение в файле database.c.