Thread: Error Handling and Header Files

  1. #1
    Registered User
    Join Date
    Jan 2005
    Posts
    42

    Error Handling and Header Files

    My first question has to do with encoutering errors in library routines. Here's a quick simple function for an example.
    Code:
    void *
    stack_pop(struct stack *s)
    {
    	if (s->top == -1) { /* stack is empty */
    		???
    	}
    
    	s->top--;
    
    	if (s->capacity - s->top - 1 >= 1.5 * __STACK_CAPACITY_INCREMENT)
    	{
    		s->capacity -= __STACK_CAPACITY_INCREMENT;
    		s->stack = realloc(s->stack, s->capacity * sizeof(void *));
    
    		if (s->stack == NULL) { /* reallocation failed */
    			???
    		}
    	}
    
    	return s->stack[1 + s->top];
    }
    In this code, some special return value is not an option for indicating an error occurred, much less the exact type of error. How is this type of situation handled in C?

    My other question has to do with .h files. Frankly, I simply don't understand how they're linked to the corresponding .c file. I've looked through .h files in other C libraries and I don't see any reference to the .c file. So my assumption is that the compiler knows to automatically look for a .c file of the same name. I tried a small test to see if this was the case:
    Code:
    /* hello.h */
    
    void hello(void);
    Code:
    /* hello.c */
    
    #include <stdio.h>
    
    void hello(void)
    {
    	printf("Hello, World!");
    	return;
    }
    Code:
    /* main.c */
    
    #include "hello.h"
    
    int main(void)
    {
    	hello();
    	return 0;
    }
    I'm compiling this with GCC on Win32. But, naturally I get the error undefined reference to 'hello'.

    So, quite simply, I don't get it. How do they get linked together?

  2. #2
    Registered User
    Join Date
    Sep 2001
    Posts
    4,912
    No where do you include, "hello.c".

  3. #3
    Registered User
    Join Date
    Jan 2005
    Posts
    42
    Nowhere do I include stdio.c either. Yet somehow I get those routines from just the header file.

  4. #4
    Software Developer jverkoey's Avatar
    Join Date
    Feb 2003
    Location
    New York
    Posts
    1,905
    You have to make sure hello.c is being included in your project and that it is being compiled.


    To clarify: I mean included IN your project, not included in the source, but in your actual project, you should have hello.c with it

  5. #5
    Registered User
    Join Date
    Jan 2005
    Posts
    42
    How exactly do I include it in my "project"? I have the .c file in the same directory as the .h file. Do I somehow have to list for GCC all the files to be included?

  6. #6
    Registered User
    Join Date
    Sep 2001
    Posts
    4,912
    Include hello.h in hello.c, and for safetyy you should be using #ifndefs.

  7. #7
    Registered User
    Join Date
    Jan 2005
    Posts
    42
    So that would mean that my main program would include hello.c instead of hello.h. But then how come every other professionally made library I've come across has .h and .c files and tells you to include the .h file into your program? I'm just confused how that works.

  8. #8
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    The .h files only include declarations and such. No statements actually go in the header files, they're all in C files. So let's say you wanted to create a library with a function called foo().
    Code:
    // foo.c
    #include <stdio.h>
    
    void foo(void)
    {
      puts("FOO!");
    }
    Then you compile the library with gcc -Wall -c foo.c. The -c switch tells gcc to only compile the file, but not link it into an executable. You'll be left with an object file called foo.o

    Now, say you're writing a program and want to use that foo library. You can either remember to add an extern void foo(void); to the top of every program you write that uses that library, or you can add that line to a foo.h file along with any other declarations the library might need to share with a program and then remember to just add #include "foo.h" to your program.

    So basically the header file just helps your program tie into the library, but the .c files in the library actually contain all the useful code.

    For instance, to use a standard C function like sqrt you need to #include <math.h>. If you look at math.h you'll see a bunch of #defines and function prototypes. There's also a pre-compiled standard C library that contains the actual functions like sqrt(). The math.h header file just tells your program what the math functions return and what parameters they expect.
    Last edited by itsme86; 01-03-2005 at 12:13 AM.
    If you understand what you're doing, you're not learning anything.

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Well at the command line, you type
    Code:
    gcc main.c hello.c
    Later on (when you have many source files), you'll use a Makefile to handle all the detail.

    Glossy Integrated Development Environments (IDEs) like Dev-C++ use things called projects (which are glorified makefiles) and you use dialogs like "add file to project".

    > and tells you to include the .h file into your program?
    There are three programs involved in creating your program
    - the compiler turns your C code into assembler code
    - the assembler turns that assembler code into an object file
    - the linker combines all the object files with the standard library (and other libraries you choose) to produce an executable file.
    Code:
    gcc -v main.c hello.c
    shows this all happening in gory detail.

    The point is, the compiler only needs hello.h in order to compile main.c, its the linker which actually needs hello.o (after being compiled from hello.c).

  10. #10
    Registered User
    Join Date
    Jan 2005
    Posts
    42
    Ok, thanks guys. I understand it now.

    Any thoughts now on the first question regarding error handling?

  11. #11
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Well in this case
    Code:
    	if (s->top == -1) { /* stack is empty */
    		???
    	}
    You could
    1. return NULL to indicate that there is no element, and rely on the programmer testing this value.
    2. set an error number and return NULL. Then have another function
    int stack_GetLastError( struct stack *s );
    to retrieve that error condiiton, and rely on the programmer calling the GetLastError function.
    3. call exit() to just kill the program.

    In this case
    Code:
    		s->stack = realloc(s->stack, s->capacity * sizeof(void *));
    		if (s->stack == NULL) { /* reallocation failed */
    			???
    		}
    It is not a fatal error at all (or indeed any error) if the code is better written
    Code:
    		void *temp = realloc(s->stack, s->capacity * sizeof(void *));
    		if (temp != NULL) { /* reallocation OK */
    			s->stack = temp;
    		}
    If you can't shrink the stack this time around, that's no biggie. You'll get another shot the next time around.
    This does not apply when you're trying to expand memory in the stack_push()

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Checking array for string
    By Ayreon in forum C Programming
    Replies: 87
    Last Post: 03-09-2009, 03:25 PM
  2. Linking header files, Source files and main program(Accel. C++)
    By Daniel Primed in forum C++ Programming
    Replies: 3
    Last Post: 01-17-2006, 11:46 AM
  3. Request for comments
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-02-2004, 10:33 AM
  4. Using c++ standards
    By subdene in forum C++ Programming
    Replies: 4
    Last Post: 06-06-2002, 09:15 AM