#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    16
    Rep Power
    0

    Compiling question...


    Our instructor gave us an assignment to "create a linked-list that will consist of 4 source code files".

    In the instructions he asks us to open the files and type the code into a new program "p10.c". In class he showed us what that would look like. Then we are supposed to compile as follows:
    gcc file1.c file2.c p10.c file3.c -o p10

    I did this. I got an error that said several things were redefined.

    My two questions are:

    1. Would I be correct in thinking that is because it sees what he told us to type and the same thing in the files it is compiling with the new one?

    2. The compiler needs either what we type OR the files, but not both?

    I e-mailed the teacher, but he hasn't replied and the assignment is due before the next class. I am trying to figure out if there is a way to do this as he has instructed? Or do I just need to do one or the other?

    Any advice?
  2. #2
  3. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,162
    Rep Power
    2222
    Your development system which you casually call "your compiler" actually is a suite of programs, only one of which is the actual compiler. The more proper term for your development system would be "integrated development environment" (IDE).

    Each source file is compiled separate and independently of the others. The compiler reads the source file and translates it to an object file. The end product of the compiler performing four separate and independent compilations of the four source files is four object files that contain object code (ie, "almost machine code") and information for the linker. Please note that "separately and independently" means that the compiler has no memory nor knowledge of what happened in any of the other compilations; the only information it has of what is in another source file comes to it through the header files.

    After calling the compiler to compile each source file, your IDE then runs the linker which takes the object files plus any library files (eg, the standard C library) and combines them together to create the executable file.

    Bottom Line: the linker needs to know what object and library files belong to the project.

    Every IDE has some form of project management. That means that in your IDE, whatever it may be, you create a new project and you add the source files to that project. Then you tell the IDE to build that project, whereupon the IDE takes the actions described above.

    What IDE are you using?

    Did you create a project and add your source files to that project?

    If you want instructions on how to do that, then you will first need to tell us which IDE you are using. The details are different for each IDE.

    BTW, if you are using gcc, then you simply pass all the source file names in the command-line invocation; eg:
    gcc -Wall file1.c file2.c p10.c file3.c -o p10

    Oops! Gee! You are using gcc!

    OK, review this statement (emphasis added):
    Originally Posted by dwise1_aol
    Please note that "separately and independently" means that the compiler has no memory nor knowledge of what happened in any of the other compilations; the only information it has of what is in another source file comes to it through the header files.
    Did you create the header files?

    Did you add #include statements to the source files to include them into those source files?
    Remember, each source file that references something in a header file needs that header file to be #include'd into it. That's just like when you use a particular standard C library function; you need to #include that function's header file into your source.
    Last edited by dwise1_aol; August 28th, 2013 at 11:06 AM.
  4. #3
  5. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,162
    Rep Power
    2222
    Originally Posted by WhatNow
    I got an error that said several things were redefined.
    Actually, you should have gotten several error/warning messages, one for each such item. Also, before each of those "redefinition" errors you should have gotten a corresponding warning that that item was undefined.

    If not, then you need to tell gcc to display all warnings. Always run gcc with the -Wall option.

    What that indicates is that you are calling functions and/or using variables before the compiler has any knowledge of them. So when the compiler encounters such an identifier, legacy behavior kicks in that creates that variable/function reference as an int, which is its default assumption. Then further down the page when the compiler finally encounters the actual declaration, it complains that the real deal is redefining its default assumption about that variable/function.

    Remember that the compiler reads the source file from top to bottom. That means that a declaration or prototype of a function has to appear somewhere above the function call. And that a variable must be declared before it can be referenced.

    Normal practice is to place all function prototypes and global variable declarations at the top of the file after the block of #include statements. If the function prototypes appear in a header file, then simply #include that header file.

    Again, always remember that you always have to tell the compiler about a function or variable or datatype before you tell the compiler to use it.
  6. #4
  7. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    16
    Rep Power
    0

    Okay..


    This could be long...

    First I will apologize for not using correct terms to communicate what I am trying to say. This is my 7th week of my first C class, so I'm not really doing that fantastic at remembering exactly how to say everything. :(

    I have a pc running windows 8, I use putty to access the school's server and log in. We do our c programming in vi in Unix. We use gcc to compile.

    What I did was type exactly what our teacher told us to type:
    Code:
    #include "prog10.h"
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct person {
      char name[20];
      int age;
      struct person *next_ptr;
    }PERSON;
    
    PERSON* createList(void);
    void print_list(PERSON*);
    void release_memory(PERSON*);
    
    int main(void)
    {
      PERSON *head = NULL;
      head = createList();
      print_list(head);
      release_memory(head);
    
      printf("Done\n");
    
      return 0;
    }
    
    PERSON* createList(void)
    {
      char answer;
      PERSON *current, *previous, *head = NULL;
    
      while(1)
      {
        printf("Add a person to the list? [y/n]\n");
        scanf("%c", &answer);
        if(answer == 'n')
          return head;
    
      current = (PERSON*)malloc(sizeof(PERSON));
    
      printf("Enter a name: \n");
      scanf("%s", current->name);
    
      printf("Enter person's age: \n");
      scanf("%i", &current->age);
    
      while(getchar()!= '\n');
      if(head == NULL)
        head = current;
      else
        previous->next_ptr = current;
    
      current->next_ptr = NULL;
    
      previous = current;
      }
    }
    
    void print_list(PERSON *person_ptr)
    {
      while(person_ptr != NULL)
      {
        printf("Name = %s\nAge = %i\n\n", person_ptr->name, person_ptr->age);
        person_ptr = person_ptr->next_ptr;
      }
    }
    
    void release_memory(PERSON *person_ptr)
    {
      PERSON *tmp_next_ptr;
      while(person_ptr != NULL)
      {
        tmp_next_ptr = person_ptr->next_ptr;
        free(person_ptr);
        person_ptr = tmp_next_ptr;
      }
      puts("Memory Released\n");
    }
    Then as instructed I compiled:

    gcc file1.c file2.c p10.c file3.c -o p10

    And got the following error*s (you are correct, it was multiple, sorry for the miscommunication).
    Code:
    p10.c:5: error: redefinition of 'struct person'
    p10.c:9: error: conflicting types for 'PERSON'
    prog10.h:9: note: previous declaration of 'PERSON' was here
    p10.c:11: error: conflicting types for 'createList'
    prog10.h:12: note: previous declaration of 'createList' was here
    p10.c:12: error: conflicting types for 'print_list'
    prog10.h:13: note: previous declaration of 'print_list' was here
    p10.c:13: error: conflicting types for 'release_memory'
    prog10.h:14: note: previous declaration of 'release_memory' was here
    p10.c:27: error: conflicting types for 'createList'
    prog10.h:12: note: previous declaration of 'createList' was here
    p10.c:59: error: conflicting types for 'print_list'
    prog10.h:13: note: previous declaration of 'print_list' was here
    p10.c:68: error: conflicting types for 'release_memory'
    prog10.h:14: note: previous declaration of 'release_memory' was here
    Looking at the errors, would be problem be because he had us type the declarations into the p10.c program even though they were included in the prog10.h that he had us include? If I remove the "#include "prog10.h"" and run the compiler I get this:

    Code:
    /tmp/cctIu1ln.o: In function `main':
    p10.c:(.text+0x0): multiple definition of `main'
    /tmp/ccJFvRM4.o:main.c:(.text+0x0): first defined here
    /tmp/cctIu1ln.o: In function `createList':
    p10.c:(.text+0x45): multiple definition of `createList'
    /tmp/ccrHTT2d.o:createFile.c:(.text+0x0): first defined here
    /tmp/cckPPZHw.o: In function `release_memory':
    releaseMemory.c:(.text+0x0): multiple definition of `release_memory'
    /tmp/cctIu1ln.o:p10.c:(.text+0x13e): first defined here
    collect2: ld returned 1 exit status
    I'm not sure how to remedy this.

    I did find that if I omitted "#include "prog.h"" and compiled

    gcc p10.c -o p10 it worked fine and the program did what it should. (which I think defeats the purpose of the assignment entirely... it seems like I need to take parts of the program he had us write out because they are in the files we are compiling. Is that correct?)
  8. #5
  9. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,162
    Rep Power
    2222
    I do not understand what's in the different files, nor which source file you showed us the listing of; I assume that it's p10.c.

    Is the PERSON struct declared in the header file, prog10.h, as I understand you to be saying? If so, then you do not need to declare it again in the source file. Indeed, it would be necessary for it to be declared in a header file if more than one source file needs to use it.

    Because the declaration of PERSON failed, so did the prototypes for createList, print_list, and release_memory. That in turn caused the cascade of errors. Because one error could be the cause of subsequent errors, a good debugging practice is to try to correct the first error reported, then re-compile.

    That second message listing looks like the output from the linker. What's in the header file, prog10.h? Do you have source code in there? It looks like the linker is complaining about multiple copies of the same functions being present. Could you please show us the listing for prog10.h?

    A header file must not contain any executable code (disregarding a few possible exceptions to this rule in C++ which are well-defined) nor declare any variables. Instead, a header file can only contain macro definitions, type declarations, enum declarations, extern statements (which mention global variables that are declared somewhere in a source file), and function prototypes.

    I suspect that you are violating that rule about what header files may contain. If so, then that is the cause of your problems.
    Last edited by dwise1_aol; August 28th, 2013 at 02:52 PM.
  10. #6
  11. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,162
    Rep Power
    2222
    Originally Posted by WhatNow
    I did find that if I omitted "#include "prog.h"" and compiled

    gcc p10.c -o p10 it worked fine and the program did what it should. (which I think defeats the purpose of the assignment entirely... it seems like I need to take parts of the program he had us write out because they are in the files we are compiling. Is that correct?)
    My understanding of your assignment is that you have one completely function program now and you need to split it up into four source files. You have four functions there, so it looks like you're expected to place each function in its own source file.

    By convention, in a multiple-file project (several of our projects have more than 100 source files) you create pairs of files: a source file and a header file with the datatypes and function prototypes for the source file. That way, any other source file that needs to call a function in that source file will #include that header file; it's a simple and fairly reliable way to keep straight which header file you need. In addition to that, type and macro definitions that multiple source files need can be kept in their own header files that have no corresponding source file.

    Just some food for thought.
  12. #7
  13. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    16
    Rep Power
    0

    Files.


    That is what I am confused about. There are 5 files, 4 that the instructor created and had us copy to the prog10 directory and the p10.c file we had to create. The code I posted is what he had us enter into p10.c. (Which as I said runs as the entire program by itself, and that is what has me confused...)

    The other files contain the following:

    file1.c
    Code:
    #include "prog10.h"
    
    
    int main (void)
    {
    
        PERSON *head = NULL;
    
    
        head = createList();
    
        print_list(head);
    
        release_memory(head);
    
        printf("Done\n");
        return 0;
    }
    file2.c
    Code:
    #include "prog10.h"
    
    
    PERSON* createList()
    {
        char    answer;
        PERSON *current, *previous, *head = NULL;
    
        while(1)
        {
    
            printf("Add a person to the List? [y/n] ");
    
            scanf("%c", &answer);
            if(answer == 'n')
                return head;
    
            current = (PERSON *)malloc(sizeof(PERSON) );
    
            printf("Enter a Name:");
            scanf("%s", current->name);
            printf("Enter persons age:");
            scanf("%i", &current->age);
    
            while(getchar() != '\n');
    
            if (head == NULL)
                head = current;
            else
                previous->next_ptr = current;
    
            current->next_ptr = NULL;
    
            previous = current;
        }
    }
    file3.c
    Code:
    #include "prog10.h"
    
    void release_memory(PERSON *person_ptr)
    {
        PERSON *tmp_next_ptr;
    
        while (person_ptr != NULL)
        {
            tmp_next_ptr = person_ptr->next_ptr;
            free(person_ptr);
            person_ptr = tmp_next_ptr;
        }
        puts("Memory Released");
    }
    prog10.h
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    
    typedef struct person {
        char name[20];
        int age;
        struct person *next_ptr;
    } PERSON;
    
    
    PERSON* createList(void);
    void    print_list(PERSON *head);
    void    release_memory(PERSON *);
    Which as you can see is most of the program he had us write in p10.c I don't understand why he had us do it this way? :confused:

    Am I understanding correctly that for this to compile and run the way it is supposed to, I need to omit all of the code that is in the other files from the p10.c file and then compile as directed?
  14. #8
  15. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,162
    Rep Power
    2222
    So then your instructor gave you the five files to begin with? In that case, the correct invocation of gcc would have been (assuming that print_list is in file4.c, which you did not list):

    gcc -Wall file1.c file2.c file3.c file4.c -o p10

    Please note that gcc does not need to know about prog10.h, since that's handled by the #include statements in the source files.

    So then your assignment is to combine the four files into one called p10.c? OK, so do that, only do not combine in what's in prog10.h, but rather just have on #include statement to pull it in. Or you could also combine in what's in the header file, but then you must not #include it -- actually, that's what #include does anyway. Then with everything in one big happy source file, then the invocation would indeed be as you had found to work:

    gcc -Wall p10.c -o p10

    Though the purpose of the exercise is beyond me. It would make much more sense to me for you to have gone in the opposite direction, splitting a single source file into multiple and then learning how to build that.

    PS

    That command you started with is bogus:

    gcc file1.c file2.c p10.c file3.c -o p10

    There's the concept of a namespace. In post-1998 C++ you can create multiple namespaces and manipulate them, but in C there is only one single namespace for the entire project. Within a namespace, you cannot have two different functions or variables by the same name. If you do, then it's a name collision which is not allowed. The reason is that every function and variable has a specific location in memory, so when you call a function or access a variable, the linker needs to know what address to insert into the code for that to happen. If there are two functions by the same name, then the linker cannot know which one's memory location to use.

    Another aspect of the single namespace in C is that everything with file scope (ie, every function and every global variable) in any source file is visible to all other source files. So print_list() in file4.c is visible to and accessible from main() in file1.c. The only way to keep a function or global variable from being visible and accessible from outside that function is to declare it as static. Please note that this does not apply to local variables with function scope, since they are not known outside their functions; declaring a local variable as static has an entirely different meaning.

    The bottom line is that by including p10.c in the build, you have duplicate copies of functions which in turn caused name collisions.
    Last edited by dwise1_aol; August 28th, 2013 at 03:42 PM.
  16. #9
  17. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    16
    Rep Power
    0
    Originally Posted by dwise1_aol
    So then your instructor gave you the five files to begin with? In that case, the correct invocation of gcc would have been (assuming that print_list is in file4.c, which you did not list):

    gcc -Wall file1.c file2.c file3.c file4.c -o p10

    Please note that gcc does not need to know about prog10.h, since that's handled by the #include statements in the source files.

    So then your assignment is to combine the four files into one called p10.c? OK, so do that, only do not combine in what's in prog10.h, but rather just have on #include statement to pull it in. Or you could also combine in what's in the header file, but then you must not #include it -- actually, that's what #include does anyway. Then with everything in one big happy source file, then the invocation would indeed be as you had found to work:

    gcc -Wall p10.c -o p10

    Though the purpose of the exercise is beyond me. It would make much more sense to me for you to have gone in the opposite direction, splitting a single source file into multiple and then learning how to build that.
    We started out with just the 3 files he gave us file1-3 and prog10.h. He had us create p10.c and type in what I posted. (Which is what made this whole thing confusing. ;) )

    We are supposed to compile the original 3 files plus p10.c.

    The command he gave us to compile the executable is:

    gcc file1.c file2.c p10.c file3.c -o p10

    If I am understanding correctly now, I should just open p10.c , delete the code that is already included in the other 3 files and compile, correct?
  18. #10
  19. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    16
    Rep Power
    0
    Originally Posted by WhatNow
    If I am understanding correctly now, I should just open p10.c , delete the code that is already included in the other 3 files and compile, correct?
    Okay, I did that and it worked perfectly! ^_^ Thank you!!!

    I just deleted all parts from p10.c that were in the other files and compiled and it worked no problem. The program ran as expected. We just didn't need the duplicate copies in p10.c, not sure why he had us add them, maybe so we could figure out we didn't need them?? ;)
  20. #11
  21. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,162
    Rep Power
    2222
    Response to Msg #9:

    Read the PS that I just added to Msg #8.

    His assignment as you have presented it to us makes absolutely no sense at all. Unless he wanted you to see what happens when names collide, but that is to be done in a classroom demonstration, not as a homework assignment.

IMN logo majestic logo threadwatch logo seochat tools logo