Thread: Undefined Reference to Main Error

  1. #1
    Registered User
    Join Date
    Feb 2009
    Posts
    36

    Undefined Reference to Main Error

    I've been studying "The C Programming Language" text and checking my answers here: The C Programming Language Answers To Exercises. I'm on exercise 4-2 and when I try to compile the answer given on the website, I get this error:
    [T3256@GURY Exercise.4-2]$ cc answer.c
    /usr/lib/gcc/i386-redhat-linux/4.3.2/../../../crt1.o: In function `_start':
    (.text+0x18): undefined reference to `main'
    collect2: ld returned 1 exit status
    I'm confused because the main function is defined at the very bottom of the answer. Here is the code:
    Code:
    /*
    **  Written by Dann Corbit as K&R 2, Exercise 4-2 (Page 73).
    **  Keep in mind that this is *JUST* a student exercise, and is
    **  light years away from being robust.
    **
    **  Actually, it's kind of embarassing, but I'm too lazy to fix it.
    **
    **  Caveat Emptor, not my fault if demons fly out of your nose,
    **  and all of that.
    */
    #include <ctype.h>
    #include <limits.h>
    #include <float.h>
    #include <signal.h>
    #include <stdio.h>
    
    int my_atof(char *string, double *pnumber)
    {
        /* Convert char string to double data type. */
        double          retval;
        double          one_tenth = 0.1;
        double          ten = 10.0;
        double          zero = 0.0;
        int             found_digits = 0;
        int             is_negative = 0;
        char           *num;
    
        /* Check pointers. */
        if (pnumber == 0) {
            return 0;
        }
        if (string == 0) {
            *pnumber = zero;
            return 0;
        }
        retval = zero;
    
        num = string;
    
        /* Advance past white space. */
        while (isspace(*num))
            num++;
    
        /* Check for sign. */
        if (*num == '+')
            num++;
        else if (*num == '-') {
            is_negative = 1;
            num++;
        }
        /* Calculate the integer part. */
        while (isdigit(*num)) {
            found_digits = 1;
            retval *= ten;
            retval += *num - '0';
            num++;
        }
    
        /* Calculate the fractional part. */
        if (*num == '.') {
            double          scale = one_tenth;
            num++;
            while (isdigit(*num)) {
                found_digits = 1;
                retval += scale * (*num - '0');
                num++;
                scale *= one_tenth;
            }
        }
        /* If this is not a number, return error condition. */
        if (!found_digits) {
            *pnumber = zero;
            return 0;
        }
        /* If all digits of integer & fractional part are 0, return 0.0 */
        if (retval == zero) {
            *pnumber = zero;
            return 1;               /* Not an error condition, and no need to
                                     * continue. */
        }
        /* Process the exponent (if any) */
        if ((*num == 'e') || (*num == 'E')) {
            int             neg_exponent = 0;
            int             get_out = 0;
            long            index;
            long            exponent = 0;
            double          getting_too_big = DBL_MAX * one_tenth;
            double          getting_too_small = DBL_MIN * ten;
    
            num++;
            if (*num == '+')
                num++;
            else if (*num == '-') {
                num++;
                neg_exponent = 1;
            }
            /* What if the exponent is empty?  Return the current result. */
            if (!isdigit(*num)) {
                if (is_negative)
                    retval = -retval;
    
                *pnumber = retval;
    
                return (1);
            }
            /* Convert char exponent to number <= 2 billion. */
            while (isdigit(*num) && (exponent < LONG_MAX / 10)) {
                exponent *= 10;
                exponent += *num - '0';
                num++;
            }
    
            /* Compensate for the exponent. */
            if (neg_exponent) {
                for (index = 1; index <= exponent && !get_out; index++)
                    if (retval < getting_too_small) {
                        get_out = 1;
                        retval = DBL_MIN;
                    } else
                        retval *= one_tenth;
            } else
                for (index = 1; index <= exponent && !get_out; index++) {
                    if (retval > getting_too_big) {
                        get_out = 1;
                        retval = DBL_MAX;
                    } else
                        retval *= ten;
                }
        }
        if (is_negative)
            retval = -retval;
    
        *pnumber = retval;
    
        return (1);
    }
    /*
    ** Lame and evil wrapper function to give the exercise the requested
    ** interface.  Dann Corbit will plead innocent to the end.
    ** It's very existence means that the code is not conforming.
    ** Pretend you are a C library implementer, OK?  But you would fix
    ** all those bleeding gaps, I am sure.
    */
    double atof(char *s)
    {
        double          d = 0.0;
        if (!my_atof(s, &d))
        {
    #ifdef DEBUG
            fputs("Error converting string in [sic] atof()", stderr);
    #endif
            raise(SIGFPE);
        }
        return d;
    }
    
    #ifdef UNIT_TEST
    char  *strings[] = {
        "1.0e43",
        "999.999",
        "123.456e-9",
        "-1.2e-3",
        "1.2e-3",
        "-1.2E3",
        "-1.2e03",
        "cat",
        "",
        0
    };
    int  main(void)
    {
        int             i = 0;
        for (; *strings[i]; i++)
            printf("atof(%s) = %g\n", strings[i], atof(strings[i]));
        return 0;
    }
    #endif
    I'd appreciate some help. Thanks.

  2. #2
    Registered User slingerland3g's Avatar
    Join Date
    Jan 2008
    Location
    Seattle
    Posts
    603
    At first glance place #endif above main.

  3. #3
    Registered User slingerland3g's Avatar
    Join Date
    Jan 2008
    Location
    Seattle
    Posts
    603
    Also are you sure you are needing to place char *strings within your #ifdef UNIT_TEST? As this may fail your main code as this references strings[].

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    If UNIT_TEST isn't defined, then main will never be in the code either.
    Not what you want, I suspect.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    Registered User
    Join Date
    Feb 2009
    Posts
    36
    I didn't write that code btw. It's just the answer I'm trying to use to check my work. I'm only on chapter 4.

  6. #6
    Registered User
    Join Date
    Sep 2008
    Location
    Toronto, Canada
    Posts
    1,834
    I concur with the above diagnosis. I'd say the #endif should go just prior to the 0 entry for the string[] initilizer list. That way, the string is legally defined but may be empty list depending on existence of UNIT_TEST.

  7. #7
    Registered User
    Join Date
    Feb 2009
    Posts
    36
    I changed the code like this:
    Code:
    #ifdef UNIT_TEST
    char  *strings[] = {
        "1.0e43",
        "999.999",
        "123.456e-9",
        "-1.2e-3",
        "1.2e-3",
        "-1.2E3",
        "-1.2e03",
        "cat",
        "",
        0
    };
    #endif
    
    int  main(void)
    {
        int             i = 0;
        for (; *strings[i]; i++)
            printf("atof(%s) = %g\n", strings[i], atof(strings[i]));
        return 0;
    }
    Now I get this error:
    [T3256@GURY Exercise.4-2]$ cc temp.c
    temp.c: In function ‘main’:
    temp.c:175: error: ‘strings’ undeclared (first use in this function)
    temp.c:175: error: (Each undeclared identifier is reported only once
    temp.c:175: error: for each function it appears in.)
    Thanks.

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Again, it's the same ordeal.
    You never create your strings array in the code because UNIT_TEST isn't defined.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    Registered User
    Join Date
    Sep 2008
    Location
    Toronto, Canada
    Posts
    1,834
    I betcha the first source code posted was correct.

    If UNIT_TEST is defined than that code includes main(). Else it doesn't.

    This .c source is meant to be linked with other source code - where main() is usually during "production". Whereas, the UNIT_TEST switch is meant to have this piece of code compiled and executed in isolation.

  10. #10
    Registered User
    Join Date
    Feb 2009
    Posts
    36
    Well all of this is beyond my level of C knowledge. I'll just have to do without this one test for now. Thanks for the help anyway guys.

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Well, if it helps, all you need to do is add:
    #define UNIT_TEST
    At the top of the source file. Then it should compile.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. An error is driving me nuts!
    By ulillillia in forum C Programming
    Replies: 5
    Last Post: 04-04-2009, 09:15 PM
  2. Another syntax error
    By caldeira in forum C Programming
    Replies: 31
    Last Post: 09-05-2008, 01:01 AM
  3. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  4. Please Help - Problem with Compilers
    By toonlover in forum C++ Programming
    Replies: 5
    Last Post: 07-23-2005, 10:03 AM
  5. UNICODE and GET_STATE
    By Registered in forum C++ Programming
    Replies: 1
    Last Post: 07-15-2002, 03:23 PM