Почему `NUMBER` в K & R" Обратный польский калькулятор "отображается как пустое в gdb? - PullRequest
0 голосов
/ 07 февраля 2019

В соответствии с K & R, Калькулятор обратного польского, уменьшена основная функция, чтобы лучше понять:

#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;
}

Я вижу, что MAXOP 5 - это /* max size of operand or operator */, что определяетсяв качестве внешней переменной, используя #define.Что я не могу понять, так это как я могу отслеживать значение MAXOP на каждом этапе запуска программы, используя gdb?

После того, как я предоставил число 10getchar() при отладке:

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 

В какой-то момент при достижении конца функции getop:

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

Вопросы:

  1. Можно ли получить доступ к значению NUMBER из оболочки linux после того, как вышеуказанная программа скомпилирована и запущена?Другими словами, создает ли директива предварительной обработки #define NUMBER '0' внешнюю переменную NUMBER, такую ​​же, как, например, переменная $ PATH в Linux?

  2. Почему p $NUMBER команда показывает void значение для внешней переменной NUMBER?

  3. Почему команда p NUMBER показывает No symbol "NUMBER" in current context.?Означает ли это, что внешняя переменная заблокирована для GDB?

Ответы [ 3 ]

0 голосов
/ 07 февраля 2019

Я вижу, что у вас есть очень ужасное неправильное понимание синтаксиса языка Си.Не для того, чтобы ругать вас, но вы пробовали изучать C из какого-то другого источника?K & R - отличная книга, но она, как известно, лаконична и предполагает, что вы уже знаете программирование.Попробуйте просмотреть списки здесь: Руководство и список книг Definitive C

======

NUMBER, MAXOP и MAXVAL являютсяконстанты.Они определяются через директиву препроцессора и являются NOT переменными.И определенно не внешние переменные , что является совершенно другим понятием.

Когда вы пишете #define NUMBER '0', он указывает компилятору заменять каждый экземпляр NUMBER в источнике на '0',Это простой поиск и замена вашего исходного кода.Он не создает переменную, и вы не можете присвоить ей значение.Поэтому просить следовать значению #define 'ed не имеет смысла.Это всегда будет то же значение, которое было записано в источнике.

Также, пожалуйста, имейте в виду, что нет прямой связи между переменными, которые вы определяете в вашей программе, и переменными среды в вашей системе.

По поводу следующих двух вопросов краткий ответ: «Потому что GDB не знает, что они существуют».Более длинный ответ: Как упоминалось ранее, ваши директивы препроцессора - это просто инструкции вашему компилятору для поиска и замены.После того, как вы покончили с ними, вам не нужно больше их хранить, и поэтому компилятор их отбросит.GDB знает столько же о вашей программе, сколько доступно в конечном двоичном файле, который генерирует компилятор.Если компилятор не упоминает ничего о NUMBER в двоичном файле, GDB даже не может знать, что он когда-либо существовал.

Теперь это не означает, что эти данные невозможно увидеть в GDB.При компиляции вы можете передать опцию -ggdb3 в GCC, чтобы позволить GCC генерировать отладочный код, специфичный для GDB.Это включает в себя подробную информацию о программе, включая все макросы и директивы препроцессора.С этим дополнительным флагом вы можете видеть значение ваших #define 'ed констант, однако помните, что они никогда не изменятся.Это обычно полезно только для наблюдения за выполнением макрофункций, что является гораздо более сложной темой.

0 голосов
/ 07 февраля 2019
Оператор

C #define не создает внешнюю переменную.Он создает так называемый макрос .

. Макросы заменяются во время перевода программы, до или в начале компиляции.Например, с #define NUMBER '0' результат будет таким, как если бы каждый экземпляр NUMBER в исходном коде был заменен на '0'.

Относительно ваших конкретных вопросов:

  1. Эти определения макросов обычно не отслеживаются в отладочной информации, которую создает компилятор (хотя такое отслеживание может быть предложено как функция), и они не делаются видимыми для командных оболочек или отладчика.

  2. В GDB $foo относится к переменной GDB с именем foo, а не к программной переменной с именем foo.GDB предоставляет отдельные переменные для удобства использования во время отладки.Они предназначены для взаимодействия с GDB и не входят в программу.Поэтому команда p $NUMBER просит GDB напечатать значение ее переменной с именем NUMBER.Такой переменной нет, поэтому GDB сообщает о ней как void.

  3. p NUMBER, где показано «Нет символа« NUMBER »в текущем контексте», поскольку нет символа NUMBER, которыйизвестен ГБД.

0 голосов
/ 07 февраля 2019

Можно ли получить доступ к значению NUMBER из оболочки linux после того, как вышеуказанная программа скомпилирована и запущена?Другими словами, создает ли директива предварительной обработки #define NUMBER '0' внешнюю переменную NUMBER, такую ​​же, как, например, переменная $ PATH в Linux?

Нет, к счастью, символы препроцессора исимволы C не отображаются в переменных оболочки при выполнении программы.

Почему команда p $ NUMBER отображает пустое значение для внешней переменной NUMBER?

Почемуp NUMBER команда show Нет символа "NUMBER" в текущем контексте.?Означает ли это, что внешняя переменная заблокирована для GDB?

NUMBER - символ препроцессора, он исчезает на этапе предварительной обработки, потому что он заменяется своим значением, компиляторомсам по себе не видит этот символ в исходном коде, который он компилирует, поэтому он не может поместить информацию о нем в данные отладки (например, tags ), поэтому он неизвестен для отладчика

p $NUMBER эквивалентно p $KQHJDSFKJQHKJSDHKJHQSJHDKJHQKJHDSJHSQD и значению void

И p NUMBER эквивалентно p KQHJDSFKJQHKJSDHKJHQSJHDKJHQKJHDSJHSQD и говорит, что символ не существует


Если я просто выполню фазу предварительной обработки после того, как добавлю #, включите в комментарий (чтобы не получать от них тысячи строк):

/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 % 

Как видите NUMBER,MAXOP, MAXVAL и BUFSIZE заменяются их значениями

...