Thread: Multi definition error of variables with global scope in Static library in C

  1. #1
    Registered User
    Join Date
    Mar 2019
    Posts
    51

    Multi definition error of variables with global scope in Static library in C

    I am trying to make a static library and I am successful to create a static library also. But when I try to use this static library into my main.c file or main project it is giving error of multiple definition of 'recsize'.
    Someone told me that it is because I am using dat_lib.h file in both files i.e. .c file of library and in main.c file two and in each compilation unit recsize is being defined. So recsize is being defined in main.c file and in library .c file too. That is why I am getting this error.
    Now I asked about the solution. I was told that use extern keyword with global variable like
    exter int recsize = sizeof(e);
    So, I used it. But still I am getting same error i.e. multiple definition of 'recsize'.
    Kindly help me out to solve the issue.

    Code:
    /*dat_lib.h file*/
        #include<stdio.h>
        #include<conio.h>
        #include<stdlib.h>
    
    
        struct emp{
             char name[40];
             int age;
             float bs;
        };
    
    
        extern void add_record(FILE *);
        extern void modify_record(FILE *);
    extern void delete_record(FILE * , FILE *);
    extern void display_record(FILE *);
    extern void query_record(FILE *);
    extern void query_name(FILE *);
    extern void query_age(FILE *);
    extern void query_bs(FILE *);
    
    
    struct emp e;
    static int recsize = sizeof(e);
    char empname[40];
    char another;
    Code:
    /*dat_lib.c file*/
    #include"dat_lib.h"
    void add_record(FILE *fp){
        another = 'Y';
        fseek(fp,0,SEEK_END);
        while(another == 'Y' || another == 'y')
        {
            printf(":::::::    Record Adding Section    :::::::\n");
            printf("Enter name, age and basic salary: \n");
            scanf("%s%d%f", e.name, &e.age, &e.bs);
            fwrite(&e,sizeof(e),1,fp);
            printf("Add more records (Y/N)\n");
            fflush(stdin); /* if you don't use it, next statement will be skipped 
            because already a character in buffer.*/
            scanf("%c", &another);
        }
    }
    void modify_record(FILE *fp){
        another = 'Y';
        while(another == 'Y' || another == 'y')
        {
            printf(":::::::    Record Modifying Section    :::::::\n");
            printf("\nEnter name of employee to modify record!\n");
            scanf("%s", empname);
            rewind(fp);
            //fseek(fp,0,SEEK_SET); it has same output as rewind() function, so is alernate of rewind() function. 
            while(fread(&e,sizeof(e),1,fp) == 1)
                {
                    if(strcmp(e.name,empname) == 0) // [Error detected] use if, not while
                    {
                        fseek(fp,-recsize,SEEK_CUR);    /* [Error detected] -1 byte is wrong we need backward record 
                        so we used -recsize. -recsize because fread has incremented next already in buffer*/
                        printf("Enter new name, age, basic salary!\n");
                        scanf("%s %d %f", e.name, &e.age, &e.bs);
                        fwrite(&e,sizeof(e),1,fp);
                        break; // [Error detected] added it
                    }
                }
                    printf("Do you want to modify more record/s (Y/N)!\n");
                    fflush(stdin);
                    another = getche();
                }
    }
    void delete_record(FILE *fp, FILE *ft){
        another = 'Y';
        while(another == 'Y' || another == 'y')
            {
                rewind(fp);
                ft = fopen("temp.dat", "wb");  /* required only to write content from fp to ft (temporary file) 
                and no read required i.e. by fread() so is used wb.*/ 
                printf(":::::::    Record Deletion Section    :::::::\n");
                printf("Enter name of employee to delete record!\n");
                scanf("%s", empname);    // empname is address of first element and &empname of first row.
                //printf("%s", empname); this statement can be used to know that what content is in empname.
                while(fread(&e,sizeof(e),1,fp) == 1)
                {
                    /*printf("fread = %d\n", fread(&e,sizeof(e),1,fp)); making trouble, 
                    it again reading next record and now putting next record in e
                    so first record was being missed to copy from fp to ft. 
                    Result can be checked by using and executing this statement.*/
                    if(strcmp(e.name,empname) != 0)            // here while was making trouble
                    {
                        printf("strcmp = %d\n", strcmp(e.name,empname)); /*it will print only non zeros 
                        because condition be true in if-statement only by being non zero and thus control 
                        comes in. If we want to print zeros too, we can use this printf statement 
                        immediate after if-block of stamements.*/
    
    
                        /*fseek(fp,-sizeof(e),SEEK_CUR);    sizeof(e), here sizeof() operator returns unsigned constant int. 
                        Here we are using -ve sign with it. That makes trouble. Why? Yet I don't know exactly.
                        Further here no need to reverse file pointer because record is always at this point i.e. in struct emp e*/
                        fwrite(&e,sizeof(e),1,ft);    /* fread() in above statement read from one file and record to stuct emp e. 
                        Then fwrite take record from struct emp e and write it on another file. This is a way to read or write or coping 
                        from one file to another file.*/                    
                    }
                        
                        /*fclose(fp);
                        fclose(ft);
                        remove("emp.dat");                     these statements were making problem here.
                        rename("temp.dat","emp.dat");
                        fp = fopen("emp.dat","wb+");         [Error detected] Opened in wb+ here is deleteing all content. 
                        So,rb+ is right choice.*/ 
                    }
                    fclose(fp);
                    fclose(ft);        // without close a file, can't be renamed nor deleted.
                    remove("emp.dat");                    
                    rename("temp.dat","emp.dat");
                    fp = fopen("emp.dat","rb+");    /* File is opened again, so that
                    if required to perform more operations on file, could be performed.*/ 
                    printf("Do you want to delete more record/s (Y/N)!\n");
                    fflush(stdin);
                    another = getche();
            }
    }
    void display_record(FILE *fp){
        long int position;
        position = ftell(fp);    /*ftell() function is used to find out the position of file pointer 
                in the file with respect to starting of the file. It returns long int i.e. 4 bytes (if int 2 bytes)
                or 8 bytes (if int 4 bytes)*/
                printf(":::::::    Record Displaying Section    :::::::\n");
                printf("Position b/rewind: %ld\n", position);
                rewind(fp);
                position = ftell(fp);
                printf("Position a/rewind: %ld\n", position);
                //fseek(fp,0,SEEK_SET);
                printf("%-15s%-5s%-10s\n", "Name", "Age", "Basic Salary");    // Instead of variables, we provided string constants.
                while(fread(&e, sizeof(e), 1, fp) == 1)
                    printf("%-15s%-5d%-10.2f\n", e.name, e.age, e.bs);
                system("pause");
    }
    void query_record(FILE *fp){
        char choice;
        rewind(fp);
        printf(":::::::    Query Section    :::::::\n");
        printf("1. Query by Name:\n");
        printf("2. Query by age:\n");
        printf("3. Query by Basic Salary:\n");
        printf("Entre your choice:\n");
        choice = getche();
        printf("\n");
        switch(choice)
        {
            case '1':
                query_name(fp);
                break;
            case '2':
                query_age(fp);
                break;
            case '3':
                query_bs(fp);
                break;
            default:
                printf("Entre correct choice:\n");    
        }
        system("pause");
        
    } // query_record(FILE *fp)
    void query_name(FILE *fp)
    {
        char name[40];
        printf("Query record by name:\n");
        printf("Enter name for Query:    ");
        scanf("%s", name);
        while(fread(&e, sizeof(e), 1, fp) == 1)
        {
            if(strcmpi(e.name,name) == 0)
            printf("%s %d %0.2f\n", e.name, e.age, e.bs);
        }
    }
    void query_age(FILE *fp)
    {
        int age;
        char choice;
        printf("Query record by age:\n");
        printf("Enter age for Query:    ");
        scanf("%d", &age);
        printf("\n");
        printf("Please select from the following:\n");
        printf("1. greater than %d\n", age);
        printf("2. less than %d\n", age);
        printf("3. equal to %d\n", age);
        printf("Enter your choice:\n");
        fflush(stdin);
        choice = getche();
        printf("\n");
        //scanf("%c", &choice);
        switch(choice)
        {
            case '1':    /* here 1 is a character because in single quote. 
                        We can take 1 as integer as well.*/
                    while(fread(&e, sizeof(e), 1, fp) == 1)
                    {
                        if(e.age > age)
                        {
                            printf("%s %d %0.2f\n", e.name, e.age, e.bs);    
                        }
                
                    }
                    break;
            case '2':
                    while(fread(&e, sizeof(e), 1, fp) == 1)
                    {
                        if(e.age < age)
                        {
                            printf("%s %d %0.2f\n", e.name, e.age, e.bs);    
                        }
                
                    }
                    break;
            case '3':
                    while(fread(&e, sizeof(e), 1, fp) == 1)
                    {
                        if(e.age == age)
                        {
                            printf("%s %d %0.2f\n", e.name, e.age, e.bs);    
                        }
                
                    }
                    break;    
                    default:
                        printf("Enter correct choice:\n");    
        }     
    }
    void query_bs(FILE *fp)
    {
                char choice;
                float bs;
                printf("Query record by basic salary:\n");
                printf("Enter basic salary for query:    ");
                scanf("%f", &bs);
                printf("\n");
                printf("Please select from the following:\n");
                printf("1. greater than %0.2f\n", bs);
                printf("2. less than %0.2f\n", bs);
                printf("3. equal to %0.2f\n", bs);
                printf("Enter your choice:\n");
                fflush(stdin);
                choice = getche();
                printf("\n");
                //scanf("%c", &choice);
                switch(choice)
                {
                    case '1':    /* here 1 is a character because in single quote. 
                                We can take 1 as integer as well.*/
                        while(fread(&e, sizeof(e), 1, fp) == 1)
                        {
                            if(e.bs > bs)
                            {
                                printf("%s %d %0.2f\n", e.name, e.age, e.bs);    
                            }
                
                        }
                        break;
                    case '2':
                        while(fread(&e, sizeof(e), 1, fp) == 1)
                        {
                            if(e.bs < bs)
                            {
                                printf("%s %d %0.2f\n", e.name, e.age, e.bs);    
                            }
                
                        }
                        break;
                    case '3':
                        while(fread(&e, sizeof(e), 1, fp) == 1)
                        {
                            if(e.bs == bs)
                            {
                                printf("%s %d %0.2f\n", e.name, e.age, e.bs);    
                            }
                
                        }
                        break;    
                    default:
                        printf("Enter correct choice:\n");    
                }
    }
    Code:
    /*main.c file*/
    #include"dat_lib.h"
    main()
    {
        
        FILE *fp;
        FILE *ft;
        char choice;
        fp = fopen("emp.dat","rb+");
        if(fp == NULL)
        {
            fp = fopen("emp.dat", "wb+");
            if(fp == NULL)
            {
            printf("File cannot be opened\n");
            system("pause");
            exit(0);
            }
        }
        while(1)
        {
        system("cls");
        printf(":::::::    Employee Database Managenment Program    :::::::\n");
        printf("1. Add New Record\n");
        printf("2. Modify to Record\n");
        printf("3. Delete to Record\n");
        printf("4. Display Records\n");
        printf("5. Query\n");
        printf("0. Exit\n");
        printf("Enter your choice: \n");
        fflush(stdin);
        choice = getche();                // getch() will not diaplay choice on screen.
        printf("\n");
        //scanf("%c", &choice);
        switch(choice)
        {
            case '1':
                system("cls");        // can be used anywhere in the program, to make the program more clean.
                add_record(fp);
                break;
            case '2':
                system("cls");
                modify_record(fp);
                break;
            case '3':
                system("cls");
                delete_record(fp,ft);
                break;
            case '4':
                system("cls");
                display_record(fp);
                break;
            case '5':
                system("cls");
                query_record(fp);
                break;
            case '0':
                fclose(fp);
                exit(0);
                break;
            default:
                printf("Enter correct choice!\n");
                system("pause");    
                break;    
        }
            
        }
        
                fclose(fp);
                system("pause");
    }
    Attached Images Attached Images Multi definition error of variables with global scope in Static library in C-multiple-definition-recsize-png 

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    26,886
    The thing is that if you involve initialisation, the declaration of the variable with external linkage is still a definition. So, you would write in the header, at file scope:
    Code:
    extern int recsize;
    Then in one source file, at file scope:
    Code:
    int recsize = sizeof(e);
    Eh, you have to do this with your other global variables too. Why do you have so many global variables, and why do you give them such poor names like e that are completely lacking in description and hence context suitable for a global context?

    I would get rid of recsize. Just use sizeof as needed. Your global variable named another looks like an extremely good candidate to be a local variable. Wait, your global variable named e is also an extremely good candidate to be a local variable. I'm going to stick my neck out and say that you're too newbie to be using global variables: force yourself to stick to local variables.

    Also, your header lacks inclusion guards.

    By the way, your indentation needs work. Keep each indent level indented by the same amount, and remember to go back indent levels as appropriate.
    Last edited by laserlight; 03-28-2019 at 10:31 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Mar 2019
    Posts
    51
    Hehe! Yup I need to do more work on my skills. Anyway thank you very much for helping me out of this chaos. Further as you asked, I am not using just sizeof(e) because I need to jump to back record and If I use -sizeof(e) then I get error i.e. implicit conversion overflow of unsigned constant. Then when I use it int recsize = sizeof(e);and -recsize it works perfectly fine.

  4. #4
    Registered User
    Join Date
    Mar 2019
    Posts
    51
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.

    Yes I am agreed and at my level I had done it before to ask help.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    26,886
    Quote Originally Posted by rm82co
    Further as you asked, I am not using just sizeof(e) because I need to jump to back record and If I use -sizeof(e) then I get error i.e. implicit conversion overflow of unsigned constant.
    Use a cast, not a whole new variable. If not, use a named constant, but sizes are expected to be stored in a size_t, which is the type of the result of sizeof.

    Explicitly declaring the variable name to have external linkage is what you're doing with the extern keyword. External linkage means that all instances of the name with external linkage refers to the same entity. Since you declared the variable at file scope, it already has external linkage, so the extern is unnecessary except to declare the variable in a way that is not also a definition.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Large number of variables needing global scope
    By megafiddle in forum C Programming
    Replies: 12
    Last Post: 09-08-2011, 02:05 AM
  2. scope of global variable vs. static
    By chiefmonkey in forum C++ Programming
    Replies: 4
    Last Post: 06-21-2009, 12:23 PM
  3. Static definition of variables
    By Milhas in forum C Programming
    Replies: 13
    Last Post: 03-30-2008, 08:22 AM
  4. scope of global variables
    By laertius in forum C++ Programming
    Replies: 4
    Last Post: 10-15-2006, 01:59 AM
  5. Replies: 2
    Last Post: 10-02-2004, 10:12 AM

Tags for this Thread