2

I have written a small C program which is assembled of several files. When I compile, I get an error for "multiple definitions".

My main.c:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "general_structs.h"

#define FOREVER for(;;)
#define INPUT_LEN 30

int main()
{
    char command[INPUT_LEN];
    char *func;
    int i;
    int t;

    FOREVER
    {
        if(scanf("%s", command) == 1)
        {
            func = strtok(command, " ");
            for(i=0;cmd[i].func != NULL;i++)
            {
                if(strcmp(func, cmd[i].name) == 0)
                {
                    (*((cmd[i].func)));
                    t = 1;
                }
            }
            if(t == 1)
            {
                printf("No such command");
            }
        }
    }   
    return 0;   
}

My mat.c file:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "general_structs.h"

#define LENGTH 100
#define SIXTEEN 16
#define SIZE 4


void read_mat()
{
    int i = 0;
    int j = 0;
    int k = 0;
    char tmp_name[LENGTH];
    char num_buffer[LENGTH];
    char *token;
    double num_list[16];
    double tmp_num = 0;

    scanf("%[^,], %s", tmp_name, num_buffer);

    token = strtok(num_buffer, ",");

    while(token != NULL)
    {
        if(strcmp(token, "0") == 0)
        {
            num_list[i] = 0;
        }
        else
        {
            tmp_num = atof(token);
            if(tmp_num == 0)        
            {
                printf("Error in parameter: %d\n", (i-1));
                break;
            }
            else
            {
                num_list[i] = tmp_num;
            }
        }   
    i++;
    token = strtok(NULL, ",");
    }

    if(!strcmp(tmp_name, "MAT_A"))
    {
        for(i=0;i<SIZE;i++)
            for(j=0;j<SIZE;j++)
            {
                mats[0].mat[0][i][j] = num_list[k];
                k++;
            }

    }
    else if(!strcmp(tmp_name, "MAT_B"))
    {
        for(i=0;i<SIZE;i++)
            for(j=0;j<SIZE;j++)
            {
                mats[1].mat[0][i][j] = num_list[k];
                k++;
            }
    }
    else if(!strcmp(tmp_name, "MAT_C"))
    {
        for(i=0;i<SIZE;i++)
            for(j=0;j<SIZE;j++)
            {
                mats[2].mat[0][i][j] = num_list[k];
                k++;
            }
    }
    else if(!strcmp(tmp_name, "MAT_D"))
    {
        for(i=0;i<SIZE;i++)
            for(j=0;j<SIZE;j++)
            {
                mats[3].mat[0][i][j] = num_list[k];
                k++;
            }
    }
    else if(!strcmp(tmp_name, "MAT_E"))
    {
        for(i=0;i<SIZE;i++)
            for(j=0;j<SIZE;j++)
            {
                mats[4].mat[0][i][j] = num_list[k];
                k++;
            }
    }
    else if(!strcmp(tmp_name, "MAT_F"))
    {
        for(i=0;i<SIZE;i++)
             for(j=0;j<SIZE;j++)
             {
                mats[5].mat[0][i][j] = num_list[k];
                k++;
             }
    }
    else
    {
        printf("No such matrix name.");
    }
}

My general_structs.h file:

#define SIZE 4
#define SIZE_NAME 5
#define SIZE_FUNC 10

typedef double matrix[SIZE][SIZE];

matrix MAT_A, MAT_B, MAT_C, MAT_D, MAT_E, MAT_F;

void read_mat(void);

struct 
{
    char name[SIZE_NAME];
    matrix *mat;
} mats[] = {
        {"MAT_A", &MAT_A},
        {"MAT_B", &MAT_B},
        {"MAT_C", &MAT_C},
        {"MAT_D", &MAT_D},
        {"MAT_E", &MAT_E},
        {"MAT_F", &MAT_F},
        {"non", NULL}
      };

struct
{
    char name[SIZE_FUNC];
    void (*func)(void);
} cmd[] = {
        {"read_mat", read_mat},
        {"not_valid", NULL}
      };

My make file:

int_loop: my_math.o int_loop.o
    gcc -g -ansi -Wall -pedantic my_math.o int_loop.o -o int_loop

int_loop.o : int_loop.c
    gcc -c -ansi -Wall -pedantic int_loop.c -o int_loop.o

my_math.o : my_math.c
    gcc -c -ansi -Wall -pedantic my_math.c -o my_math.o

I have been trying to solve this issue with various techniques but yet with no success.

The error I recieve is:

gcc -g -Wall -ansi -pedantic main.o mat.o -o mamantest
mat.o:(.data+0x0): multiple definition of `mats'
main.o:(.data+0x0): first defined here
mat.o:(.data+0x70): multiple definition of `cmd'
main.o:(.data+0x70): first defined here
collect2: ld returned 1 exit status
make: *** [mamantest] Error 1

Why does this error occurs? How do I solve this?

Thanks

JinKazama
  • 81
  • 3
  • 15

1 Answers1

4

In the header file you define the variables mats and cmd, meaning both translation units (both source files that includes the header file) will have those defined.

The variables should be defined only in a single place, in a single source file, like

struct mat mats[7] = { ... };

The above defines the array mats, and like I said should be done in only one place.

For the other source file you declare the variables, which can be done in the header file like e.g.

extern struct mat
{
    ...
} mats[7];

The above declare the variable mats as an array of seven mat structures. It also define the structure so it can be used to e.g. define the array.


After modifications suggested above, the complete header file should look something like

// First header include guards (see https://en.wikipedia.org/wiki/Include_guard)
#ifndef GENERIC_STRUCTS_H
#define GENERIC_STRUCTS_H

#define SIZE 4
#define SIZE_NAME 5
#define SIZE_FUNC 10

typedef double matrix[SIZE][SIZE];

// Declare the variables (note the added use of the extern keyword)
extern matrix MAT_A, MAT_B, MAT_C, MAT_D, MAT_E, MAT_F;

void read_mat(void);

// Define a structure named mat (note added structure tag name)
struct mat
{
    char name[SIZE_NAME];
    matrix *mat;
};

// Define a structure named command (note added structure tag name)
struct command
{
    char name[SIZE_FUNC];
    void (*func)(void);
};

// Now declare variables of the previous structures
extern struct mat mats[7];
extern struct command cmd[2];

// End of header include guard
#endif

That header file only declares variables, and can be included in all your source files.

Then in a single source file (for example your main.c file) you do the actual variable definitions:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "general_structs.h"

matrix MAT_A, MAT_B, MAT_C, MAT_D, MAT_E, MAT_F;

struct mat mats[7] = {
    {"MAT_A", &MAT_A},
    {"MAT_B", &MAT_B},
    {"MAT_C", &MAT_C},
    {"MAT_D", &MAT_D},
    {"MAT_E", &MAT_E},
    {"MAT_F", &MAT_F},
    {"non", NULL}
};

struct command cmd[2] = {
    {"read_mat", read_mat},
    {"not_valid", NULL}
};

#define FOREVER for(;;)
#define INPUT_LEN 30

int main()
{
    ...
}

The important thing you need to learn here is that there is a difference between declaring and defining something.

A declaration is basically telling the compiler that "this thing exists somewhere", and a definition is telling the compiler "this is the thing".

The problem is that unless a thing has already been declared, a definition is also a declaration, and many simply call these combined definitions/declarations just declaration, which muddles the whole concept up a bit.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • If I do that I won't have a "$.h" file (general_structs.h). As it is part of the task to have one.. – JinKazama May 23 '16 at 18:33
  • @JinKazama You still need the header file for the *structure* definitions, the `matrix` type alias, and the *declarations* of the variables. You just need to move the *definitions* of those variables into a single source file. Updated my answer with a modified header file. – Some programmer dude May 24 '16 at 05:23
  • Hey, Thanks for your very infromative answer. if the "defining" part of the struct should only be in a single source file (for example, "main.c"), then the other file ("mat.c") won't know these structs. Thats why I assumed that they should be in a header, where all sources can approach and read. Isnt it correct? – JinKazama May 24 '16 at 14:24
  • @JinKazama Defining a structure and defining a variable are two different things. A structure definition is a compiler-only thing, once the compiler has the structure definition it's not needed anymore, and it's not save into the object files. Variable definitions, on the other hand, *are* stored in the object files. That's why defining a variable in a header file can lead to multiple definition errors, because it will be defined in two or more object files. So like in my example, the definition of the actual structure can be in the header file, but not the definition of the variables. – Some programmer dude May 24 '16 at 14:32
  • Thanks again for your fast and informative answer. So if I define the variables in 1 source file, "main.c", the other source file "mat.c" will know these variables if I call them? – JinKazama May 24 '16 at 14:36
  • @JinKazama Yes if they are *declared* in that source file, for example by having the declarations in the header file as I shown. – Some programmer dude May 24 '16 at 14:37
  • I just did exactly what you offered and compiled. I put your "defining" structs block in my "main.c". I get a huge error output. don't think it's the right way. – JinKazama May 24 '16 at 14:47