0

As per K&R, Reverse Polish Calculator, decreased the main function, in order to get better understanding:

#include <stdio.h>
#include <stdlib.h>
#define NUMBER '0'
#define MAXOP 5

void push(double);
int pop(void);
int getop(char []);

int main(){
    int type;
    char s[MAXOP];
    double op2;
    while ((type=getop(s))!=EOF){
        switch(type):
            case NUMBER:
                push(atof(s));
                printf("\t%s\n",s);
    }

}



#define MAXVAL 100

char val[MAXVAL];
int sp;

void push(double f){
    if (sp<MAXVAL)
        val[sp++]=f;
}

int pop(void){
    if (sp>0)
        return val[--sp];
}

#include <ctype.h>

int getch(void);
void ungetch(int);

int getop(char s[]){
    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;
}


#define BUFSIZE 100

char buf[BUFSIZE];
int bufp=0;

int getch(void){
    return (bufp>0)?buf[--bufp]:getchar();
}

int ungetch(int c){
    if (bufp>=BUFSIZE)
        printf("ungetch: too many characters\n");
    else 
        buf[bufp++]=c;
}

I can see, that the MAXOP 5 is /* max size of operand or operator */, which is being defined as external variable, using #define. What I can't figure out, is how can I actually track the value of of MAXOP, at each stage of the program run, using gdb?

After I have provided the number 10 to the getchar(), while debugging:

14                      while ((type=getop(s))!=EOF){
(gdb) n

Breakpoint 14, getop (s=0x7efff5dc "\n") at t.c:47
47                      while ((s[0]=c=getch())==' '||c=='\t')
(gdb) p c
$22 = 10
(gdb) n

Breakpoint 31, getch () at t.c:72
72                      return (bufp>0)?buf[--bufp]:getchar();
(gdb) n
10

Breakpoint 34, getch () at t.c:73
73              }
(gdb) n 

At some point, when reaching the end of getop function:

Breakpoint 30, getop (s=0x7efff5dc "10") at t.c:62
62                      return NUMBER;
(gdb) p number
No symbol "number" in current context.
(gdb) p (NUMBER)
No symbol "NUMBER" in current context.
(gdb) p $NUMBER
$39 = void
(gdb) n
63              }
(gdb) n

Breakpoint 2, main () at t.c:15
15                              switch(type){
(gdb) p type
$40 = 48
(gdb) p NUMBER
No symbol "NUMBER" in current context.
(gdb) p /s NUMBER
No symbol "NUMBER" in current context.
(gdb) p /d $NUMBER
$41 = Value can't be converted to integer.
(gdb) p $NUMBER
$42 = void

Questions:

  1. Can the value of NUMBER be accessed from the shell of linux, after the above program has been compiled, and run? In other words, does the preprocessing directive #define NUMBER '0' creates the external variable NUMBER that is the same as, for instance, variable $PATH on Linux?

  2. Why does the p $NUMBER command is showing void value for the external variable NUMBER?

  3. Why does the p NUMBER command show No symbol "NUMBER" in current context.? Does it mean, that the external variable is blocked for gdb?

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
readonly
  • 89
  • 7
  • 5
    `NUMBER` is not a symbol but a preprocessor define. All preprocessor defines are gone once the program is compiled. – Jabberwocky Feb 07 '19 at 12:33
  • The preprocessor replaces all occurrences of `NUMBER` with `'0'` before compilation begins, and `'0'` is not a variable. – Weather Vane Feb 07 '19 at 12:45
  • If you compile your program with the `-g3` option to gcc, then in any not-too-old gdb you can type `macro expand NUMBER`, `macro expand MAXVAL ` etc. to see its value if you're stopped at a point in the range where the macro has a value. – Mark Plotnick Feb 07 '19 at 20:48

3 Answers3

1

Can the value of NUMBER be accessed from the shell of linux, after the above program has been compiled, and run? In other words, does the preprocessing directive #define NUMBER '0' creates the external variable NUMBER that is the same as, for instance, variable $PATH on Linux?

No, fortunately the preprocessor symbols and the C symbols are not mapped in shell variables when you execute a program.

Why does the p $NUMBER command is showing void value for the external variable NUMBER?

Why does the p NUMBER command show No symbol "NUMBER" in current context.? Does it mean, that the external variable is blocked for gdb?

NUMBER is a preprocessor symbol, it disappear during the preprocessing phase because it is replaced by its value, the compiler by itself doesn't see that symbol in the source it compiles, so it cannot put information about it in the debug datas (e.g. tags), so it is unknown for the debugger

So p $NUMBER is equivalent of p $KQHJDSFKJQHKJSDHKJHQSJHDKJHQKJHDSJHSQD and value void

And p NUMBER is equivalent of p KQHJDSFKJQHKJSDHKJHQSJHDKJHQKJHDSJHSQD and says the symbol doesn't exist


If I just do the preprocessing phase after I put your #include in comment (to not get thousands of lines from them) :

/tmp % gcc -E c.c
# 1 "c.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "c.c"





void push(double);
int pop(void);
int getop(char []);

int main(){
    int type;
    char s[5];
    double op2;
    while ((type=getop(s))!=EOF){
        switch(type):
            case '0':
                push(atof(s));
                printf("\t%s\n",s);
    }

}





char val[100];
int sp;

void push(double f){
    if (sp<100)
        val[sp++]=f;
}

int pop(void){
    if (sp>0)
        return val[--sp];
}



int getch(void);
void ungetch(int);

int getop(char s[]){
    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 '0';
}




char buf[100];
int bufp=0;

int getch(void){
    return (bufp>0)?buf[--bufp]:getchar();
}

int ungetch(int c){
    if (bufp>=100)
        printf("ungetch: too many characters\n");
    else
        buf[bufp++]=c;
}
/tmp % 

As you see NUMBER, MAXOP, MAXVAL and BUFSIZE are replaced by their value

Community
  • 1
  • 1
bruno
  • 32,421
  • 7
  • 25
  • 37
0

I can see that you have some very dire misunderstanding of the C language syntax. Not to berate you, but have you tried learning C from some other source? K&R is a great book, but it is notoriously concise and assumes that you already know programming. Try going through the lists here: The Definitive C Book Guide and List

======

NUMBER, MAXOP and MAXVAL are constants. They are defined through a pre-processor directive, and are NOT variables. And definitely not external variables which is a vastly different concept.

When you write #define NUMBER '0', it instructs the compiler to replace every instance of NUMBER in the source with '0'. It is simple search and replace on your original source code. It does not create a variable and you cannot assign a value to it. So, asking to follow the value of a #define'ed value makes no sense. It is always going to be the same value that was written in the source.

Also, please be clear that there is no direct relation between variables you define in your program and the environment variables on your system.

About the next two questions, the short answer is, "Because GDB doesn't know they exist". Longer Answer: As mentioned earlier, your pre-processor directives are simply instructions to your compiler for a search and replace. Once done with them, there is no need to keep them around for any longer and hence the compiler will discard them. GDB only knows as much about your program as is available in the final binary that the compiler generates. If the compiler doesn't mention anything about NUMBER in the binary, GDB cannot even know that it ever existed.

Now, that does not mean that it is impossible to see this data in GDB. When compiling, you can pass the -ggdb3 option to GCC to enable GCC to generate debugging code specific to GDB. This includes detailed information about the program including all the macros and pre-processor directives. With this extra flag, you can see the value of your #define'ed constants, however, remember, they will never change. This is generally only useful for seeing the execution of macro functions which is a much more advanced topic.

darnir
  • 4,870
  • 4
  • 32
  • 47
  • The book list has gone complete crap. It is no longer a list of recommended books. But obviously stay clear of K&R for any other purpose than archaeology. – Lundin Feb 07 '19 at 13:54
  • Has it? I genuinely have no idea. I've been linking to it for years now. I hear king is a good book, but I haven't read any, so can't talk from experience. – darnir Feb 07 '19 at 14:57
  • [The C book list has gone haywire. What to do with it?](https://meta.stackoverflow.com/questions/355588/the-c-book-list-has-gone-haywire-what-to-do-with-it) The post was deleted and undeleted, and the very same problems remain 18 months later. – Lundin Feb 07 '19 at 15:25
0

C’s #define statement does not create an external variable. It creates what is called a macro.

Macros are replaced during program translation, before or early in compilation. For example, with #define NUMBER '0', the result is as if every instance of NUMBER in the source code were replaced with '0'.

Regarding your specific questions:

  1. These macro definitions are typically not tracked in the debugging information that the compiler produces (although such tracking may be offered as a feature), and they are not made visible to command shells or the debugger.

  2. In GDB, $foo refers to a GDB variable named foo, not a program variable named foo. GDB provides separate variables as a convenience to use during debugging. They are for interacting with GDB and do not come fro the program. So the command p $NUMBER asks GDB to print the value of its variable named NUMBER. There is no such variable, so GDB reports it as void.

  3. p NUMBER shows “No symbol "NUMBER" in current context” because there is no symbol NUMBER that is known to GDB.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Got you. Last question, how does `case NUMBER` return `1`, if every instance of `NUMBER` is replaced with '0'? In other words, how does the switch differentiate, whether the `case NUMBER` is matching or not?? – readonly Feb 07 '19 at 14:15
  • 1
    @readonly: `case NUMBER:` does not return anything. It is a label, not an executable statement. It is a label for the `switch` statement. During macro replacement, it is replaced with `case '0':`. Then, when the `switch (type)` executes, if `type` equals `'0'`, program control goes to the `case '0':` label. – Eric Postpischil Feb 07 '19 at 14:17