Thread: Why is my symbolic constant not global? K&R problem related

  1. #1
    Registered User
    Join Date
    Apr 2009
    Posts
    16

    Why is my symbolic constant not global? K&R problem related

    Hi,

    I'm having a problem with one of the sample programs in the K&R book (second edition). Its the calculator program in chapter 4.

    A good portion of questions in that chapter revolve around this program (whose source code they have provided). So i've tried compiling it, and it won't compile!

    The problem appears to be that the symbolic constant "NUMBER" in polishCalc.c isn't being recognized in getop.c . Its declared outside all functions in polishCalc.c, so I don't understand why it isn't being recognized in getop.c. Interestingly enough, global variables seem to be recognized between the two source files... it is only with global symbolic constants that I'm having this problem.
    It fails to work with and without "extern" before NUMBER.

    Since the use of the constant is so trivial, it would take about .02 seconds to get the program to compile and work correctly. But why it isn't working is bothering me so much that I had to seek help.

    Here's the code for the 2 aforementioned source files:

    Code:
    /*THIS IS polishCalc.c*/
    
    #include <stdlib.h>
    #include <stdio.h>
    
    
    #define MAXOP 100
    #define NUMBER 0
    
    int getop(char s[]);
    void push(double d);
    double pop();
    
    
    
    void polishCalc()
    {
        int type;
        double op2;
        char s[MAXOP];
    
        while( (type = getop(s))  != EOF )
        {
            switch(type)
            {
                case NUMBER:
                    push(atof(s));
                    break;
                case '+':
                    push(pop() + pop());
                    break;
                case '*':
                    push(pop() * pop());
                    break;
                case '-':
                    op2 = pop();
                    push(pop() - op2);
                    break;
                case '/':
                    op2 = pop();
                    if(op2 == 0)
                        printf("Error: Divisor is 0");
                    else
                        push(pop() / op2);
                    break;
                case '\n':
                    printf("\t%.8g\n", pop());
                    break;
                default:
                    printf("Error: Unknown command %s\n", s);
                    break;
    
            }
        }
    }
    Code:
    /*THIS IS getop.c*/
    
    
    #include <stdio.h>
    #include <ctype.h>
    
    
    int getch(void);
    void ungetch(int);
    
    int getop(char s[])
    {
        extern int NUMBER;
        
        int i, c;
    
        while( (s[0] = c = getch()) == ' ' || c == '\t')
            ;
        s[1] = '\0';
    
        if(!isdigit(c) && c != '.')
            return c;
    
        i = 0;
    
        if(isdigit(c))
        {
            while(isdigit( s[++i] = c = getch() ))
                ;
        }
        
    
    
        if(c == '.')
        {
            while(isdigit( s[++i] = c = getch() ));
            ;
        }
    
        s[i] = '\0';
        if(c != EOF)
            ungetch(c);
    
    
        return NUMBER;
                
    
    }
    Can anyone help me out? Here are the 2 other referenced source files needed to completely compile the program if you need to:

    Code:
    /*THIS IS popPush.c*/
    
    #include <stdio.h>
    
    #define MAXVAL 100
    
    int sp = 0;
    double val[MAXVAL];
    
    void push(double f)
    {
        if(sp < MAXVAL)
            val[sp++] = f;
        else
            printf("Empty: stack full, can't push %g\n", f);
    
    }
    
    int pop(double f)
    {
        if(sp < 0)
            return val[--sp];
        else
        {
            printf("Error: Stack empty\n");
            return 0.0;
        }
    
    }
    Code:
    /*THIS IS getUnget.c*/
    
    #include <stdio.h>
    
    #define BUFSIZE 100
    
    char buf[BUFSIZE];
    int bufp = 0;
    
    int getch(void)
    {
        return (bufp > 0) ? buf[--bufp] : getchar();
    }
    
    void ungetch(int c)
    {
        if (bufp >= BUFSIZE)
            printf("ungetch: too many characters\n");
        else
            buf[bufp++];
    }

  2. #2
    Registered User
    Join Date
    Dec 2007
    Posts
    2,675
    Put your #defines into a header file which you include in the .c files. #defines are only visible in the file in which they're defined.

  3. #3
    Registered User
    Join Date
    Apr 2009
    Posts
    16
    Ah! Looks like the gods of C have an error in their book!

    Thanks... it was driving me crazy.

  4. #4
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Code:
    /*THIS IS polishCalc.c*/
    
    #include <stdlib.h>
    #include <stdio.h>
    
    
    #define MAXOP 100
    #define NUMBER 0
    #define statements don't declare an actual variable for you to reference elsewhere via an extern statement. What happens with NUMBER (within polishCalc.c only) is that instances of the token/symbol NUMBER are replaced with its #define'd value of 0 as the code is compiled... it, the symbol NUMBER, is simply understood by the compiler to mean 0 because of the #define when it encounters the symbol.


    When you write something like:
    Code:
    #define BUFSIZE 100
    
    char buf[BUFSIZE];
    
    ...
    
    
    #define MAXVAL 100
    
    int sp = 0;
    double val[MAXVAL];
    
    void push(double f)
    {
        if(sp < MAXVAL)
            val[sp++] = f;
    The compiler essentially sees the following:
    Code:
    char buf[100];
    
    ...
    
    int sp = 0;
    double val[100];
    
    void push(double f)
    {
        if(sp < 100)
            val[sp++] = f;
    So it's basically a find-and-replace mechanism - find all instances of the defined symbols and replace with the given value.



    Code:
    /*THIS IS getop.c*/
    
    
    #include <stdio.h>
    #include <ctype.h>
    
    
    int getch(void);
    void ungetch(int);
    
    
    int getop(char s[])
    {
        extern int NUMBER;
    This tells your linker that there exists an integer in another source file called NUMBER. As I stated, the #define does not create an actual integer variable called NUMBER. Since the variable does not exist, the linker should complain that it cannot find the variable.

    rags_to_riches suggestion, to put the #define in a header and include that header in the necessary source files, makes the symbol NUMBER visible to any source file which includes the header but it still is not an actual instance of an integer variable (you wouldn't need the extern line at all).
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Class related problem
    By Gnoober in forum C++ Programming
    Replies: 3
    Last Post: 10-07-2002, 10:11 PM
  2. Problem comparing string from text file with string constant
    By XenoCodex Admin in forum C++ Programming
    Replies: 3
    Last Post: 07-25-2002, 10:17 AM
  3. C++ Compiler Problem
    By Prog.Patterson in forum C++ Programming
    Replies: 0
    Last Post: 05-02-2002, 10:17 AM
  4. queued signals problem, C programming related
    By Unregistered in forum Linux Programming
    Replies: 3
    Last Post: 01-22-2002, 12:30 AM
  5. problem with output
    By Garfield in forum C Programming
    Replies: 2
    Last Post: 11-18-2001, 08:34 PM