1

After changing the code, I got new error in database_definitions.h header file. The error is near the 'extern const Lookup_Table TableLookup[TABLE_COUNT];' and mentioned the error in the code with comments next to it. I also got warning in 'database.c' file near the return &(TableLookup[index]); in the 'Lookup_Table* GetTableMetadata(char *tableName)' function. The error is pasted in the code next to it. Kindly review and help me in solving in this issue.

**database.c**:
    const Lookup_Table TableLookup[TABLE_COUNT]=
{
    {
        .tableName          = "Folder_Table",
        //        .tableInitializer   = (void*)&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 = "\0",         .pointerOffset = 0 }},
    },
    {
        .tableName          = "Item_Table",
        //        .tableInitializer   = (void*)&InitItem_Table,
        .tableMemory        = sizeof(Item_Table),
        .columns            = 4,
        .columnNames        = {"ItemID\0","FolderID\0","field1\0","field2\0"},
        .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 = "\0", .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 &(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;
}
user3723478
  • 31
  • 1
  • 2
  • 8
  • Looks like TableLookup in database_definitions.h is defined (via the include) in both database.c and main.c. The compiled object file for database.c and main.c each contain a copy of it so the linker sees duplicate definitions and complains. Can you define the table in database.c? – Brian Walker Jun 25 '14 at 17:24
  • `const Lookup_Table TableLookup[TABLE_COUNT]={...}` doesn't belong in your header file. It should be `extern const Lookup_Table TableLookup[TABLE_COUNT];` in the header and defined in a single source file, or `static` in the header, which although duplicative per translation unit, would still work for your needs. – WhozCraig Jun 25 '14 at 17:25
  • @BrianWalker I have other functions in further that will link with TableLookup and I need to define in the database_definitions.h header file. Is there another way to get rid of this issue? – user3723478 Jun 25 '14 at 17:47
  • @WhozCraig Thanks for the reply. I did not understand what you were saying. Where Should I change the name to extern const Lookup_Table TableLookup? – user3723478 Jun 25 '14 at 17:50
  • Remove the entire TableLookup block of code in database_definitions.h and put it in database.c. In database_definitions.h add "extern const Lookup_Table TableLookup[TABLE_COUNT];". This will allow other files to see TableLookup but only define the actual data for TableLookup once. – Brian Walker Jun 25 '14 at 17:59
  • @BrianWalker When I do that, I am getting below mentioned errors. 1.Unknown type name 'Lookup_Table'. 2.use of undeclared identifier 'TABLE_COUNT'. 3.Unknown type name 'Lookup_Table' – user3723478 Jun 25 '14 at 18:24
  • [Read this](http://stackoverflow.com/questions/1433204/how-do-i-share-a-variable-between-source-files-in-c-with-extern-but-how). – WhozCraig Jun 25 '14 at 18:27
  • You need to post your updated code to see exactly what you did and where you put the new definitions. – Brian Walker Jun 25 '14 at 19:02
  • I have posted my updated code. Please review it – user3723478 Jun 25 '14 at 20:36
  • You must defined types before using them. database.c needs to #include "database.h" before defining the table because it won't know the types. In database_definitions.h the extern for TableLookup needs to go at the end after the types is uses have been defined. – Brian Walker Jun 25 '14 at 21:00
  • Yeah, It worked. I have included #include "database.h" in 'database.c' file. There is no error now but the warning still exists. Kindly look at the warning in database.c which is mentioned in the comments. – user3723478 Jun 25 '14 at 21:19

3 Answers3

2

You are defining TableLookup in your header file, which you include from multiple source (and because of that, object) files. This causes it to be defined in all object files which include that header, and that results in the linker spurting out those errors.

What you should do is declare TableLookup as extern and then define it in database.c (or some other file where it fits). So, in database_definitions.h:

extern const Lookup_Table TableLookup[ TABLE_COUNT ];

And in database.c:

#include "database_definitions.h"

/* ... */

const Lookup_Table TableLookup[TABLE_COUNT]=
{
    {
        .tableName          = "Folder_Table",
//        .tableInitializer   = (void*)&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 = "\0",         .pointerOffset = 0 }},
    },
    {
        .tableName          = "Item_Table",
//        .tableInitializer   = (void*)&InitItem_Table,
        .tableMemory        = sizeof(Item_Table),
        .columns            = 4,
        .columnNames        = {"ItemID\0","FolderID\0","field1\0","field2\0"},
        .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 = "\0", .pointerOffset = 0}},
    }
};

This makes all of the source files where you include database_definitions.h know that a variable exists, but they do not contain explicit definitions. Instead, the linker is tasked with "connecting" these references to outer symbols with the places where the symbols are defined.

geomaster
  • 489
  • 5
  • 9
  • Thank you for the reply. I have updated my code. I got new error and mentioned in the above code. Please review it. error: Unknown type name 'Lookup_Table' and one warning in the database.c file. – user3723478 Jun 25 '14 at 20:34
  • In `database_definitions.h`, move the `extern const...` to the end of the file, so it understands the type `Lookup_table`. As for the other error in `database.c`, it's because you have defined the lookup table as `const`, but you're returning a non-`const` pointer from the function. Change the return type of `GetTableMetadata` to `const Lookup_Table*`. – geomaster Jun 25 '14 at 20:36
  • Are you asking me to replace 'Lookup_Table* GetTableMetadata(char *tableName' to 'const Lookup_Table* GetTableMetadata(char *tableName)'?? when I did that, I got error: Conflicting types for 'GetTableMetadata' – user3723478 Jun 25 '14 at 20:40
  • To change a function signature, you need to change it both in the .h and .c files. Before you ask on StackOverflow next time, I advise you to get some deeper understanding of the basics e.g. by going through a C beginner's guide. – geomaster Jun 25 '14 at 22:29
0

TableLookup is an array, and shouldn't be defined on .h.

Here's what happened:

two files included database_definitions.h - database.c and main.c Both have the array definition in the matching object files - database.o and main.o When the linker tries to merge the two files it fails because the TableLookup is defined twice.

TableLookup must be defined in one of the .c files - preferably database.c, then any .c file that wants to use it must add:

extern const Lookup_Table TableLookup[TABLE_COUNT];

or better yet, add the extern to database.h and any .c that includes it will have the extern and be able to use it

Shlomi Agiv
  • 1,183
  • 7
  • 17
  • Thank you for the reply. I have updated my code. I got new error and mentioned in the above code. Please review it. error: Unknown type name 'Lookup_Table' and one warning in the database.c file. – user3723478 Jun 25 '14 at 20:35
0

although I am a bit late to the party you can use:

clang compare.c -o compare -l cs50

in your terminal, the make command should work after... for those newbies you use your file and program name not 'compare', and the ' ' are not part of it, of course you would also replace the 'cs50' library with what ever library you are using, in this case I was using cs50. the l before cs50 stands for library.

https://clang.llvm.org/docs/ClangCommandLineReference.html

ryanwebjackson
  • 1,017
  • 6
  • 22
  • 36