Разный вывод в GCC и Visual Studio

Я попытался написать программу на CPP, которая получает инфиксное выражение, преобразует его в постфиксное выражение, а затем вычисляет выражение, используя выполненный мной стек-класс. Я думал, что то, что я написал, работает, потому что я провел несколько тестов в Visual Studio. Но я не знаю почему, тесты дают результат X в Visual Studio и результат Y в GCC. Например, когда я запускаю программу и ввожу (5+3)*((20/10)+(8-6)) в Visual Studio, она печатает 32. С другой стороны, в GCC печатается 0.

Итак, мой вопрос: знает ли кто-нибудь, что может вызвать эту разницу? Может в компиляторах что-то другое?

Я думаю, что это может быть вызвано неопределенным поведением. Но даже если это так, я понятия не имею, где он вызывается...

(Кстати, в GCC вместо разделения Stack.h в другой файл я просто написал его выше основного - вывод в Visual Studio все равно отличается)

основной.cpp:

#include "Stack.h"
#include <iostream>
#include <string>
#include <cmath>

using namespace std;

bool operatorsPrecedenceCheck(string& str, Stack<char>& stk, const char& ch)
{
    if (ch == '+' || ch == '-')
    {
        Stack<char> help(stk.getSize());
        char stkTop = '\0';
        if (!stk.isEmpty())
            stkTop = stk.top();
        while (!stk.isEmpty() && stkTop != '(')
        {
            stkTop = stk.top();
            if (stk.top() == '*' || stk.top() == '/')
            {
                str += stk.pop();
                str += ' ';
            }
            else
                help.push(stk.pop());
        }
        while (!help.isEmpty())
            stk.push(help.pop());

        stk.push(ch);

        return 1;
    }
    else if (ch == '*' || ch == '/')
    {
        stk.push(ch);

        return 1;
    }


    return 0;

}
bool parenthesisCheck(string& str, Stack<char>& stk, const char& ch)
{
    if (ch == '(')
    {
        stk.push(ch);

        return 1;
    }
    else if (ch == ')')
    {
        while (stk.top() != '(')
        {
            str += stk.pop();
            str += ' ';
        }
        stk.pop();

        return 1;
    }

    return 0;

}

string infixToPostfix(const string& exp)
{
    string str = "";
    Stack<char> stk(exp.length());
    bool actionExecuted = 0;
    for (int i = 0; i < exp.length(); ++i)
    {
        actionExecuted = parenthesisCheck(str, stk, exp[i]);
        if (!actionExecuted)
            actionExecuted = operatorsPrecedenceCheck(str, stk, exp[i]);
        if (!actionExecuted)
        {
            if (exp[i] >= '0' && exp[i] <= '9')
            {
                for (; exp[i] >= '0' && exp[i] <= '9'; ++i)
                    str += exp[i];

                str += ' ';
                --i;
            }
            else
                throw"An illegal value in the expression\n";
        }
    }
    while (!stk.isEmpty())
    {
        str += stk.pop();
        str += ' ';
    }

    str = str.substr(0, str.length() - 1); //Cause of space

    return str;

}

int getValueFromString(const string& str, int& i)
{
    int result = 0;
    int amountOfDigits = 0;
    while (str[i + amountOfDigits] >= '0' && str[i + amountOfDigits] <= '9')
        ++amountOfDigits;

    for (int j = pow(10, amountOfDigits - 1); j >= 1; j /= 10)
        result += (str[i++] - '0') * j;
    --i;

    return result;
}

float calcPostfix(const string& str)
{
    Stack<int>stk(str.length() / 2);
    for (int i = 0; i < str.length(); i += 2)
    {
        if (str[i] >= '0' && str[i] <= '9')
            stk.push(getValueFromString(str, i));
        else if (str[i] == '/')
            stk.push((float)1 / stk.pop() * stk.pop());
        else if (str[i] == '*')
            stk.push(stk.pop() * stk.pop());
        else if (str[i] == '+')
            stk.push(stk.pop() + stk.pop());
        else if (str[i] == '-')
            stk.push(-1 * (stk.pop() - stk.pop()));
        else
            throw"Unknown Operator in Calculating Postfix\\n";
    }

    return stk.top();

}

int main()
{
    try
    {
        string exp;
        cout << "enter an infix expression as a string" << endl;
        cin >> exp;
        string postfix = infixToPostfix(exp);
        cout << postfix << endl;
        cout << calcPostfix(postfix) << endl;
    }
    catch (const char* exc)
    {
        cout << exc;
        exit(-1);
    }
    catch (...)
    {
        cout << "Unknown Error has occured\\n";
        exit(-1);
    }

    return 0;

}

Стек.h:

#ifndef MYSTACK_H
#define MYSTACK_H

template <class T>
class Stack
{
    //Inner class help
    void swap(Stack<T> &a, Stack<T>& b);

    T* data;
    int capacity;
    int size;
public:
    //Constructors & Destructor
    Stack();
    Stack(int capacity_);
    Stack(const Stack<T>& toCopy);
    Stack(Stack<T>&& toMove);
    ~Stack();

    //Methods
    int getCapacity() const;
    int getSize() const;
    void clear();
    bool isEmpty() const;
    bool isFull() const;
    T pop();
    void push(const T& toInsert);
    T top() const;

    //Operators
    Stack<T>& operator= (const Stack<T>& toAssign);
    Stack<T>& operator=(Stack<T>&& toMove);
};

//Inner class help
template<class T>
void Stack<T>::swap(Stack<T>& a, Stack<T>& b)
{
    T* temp_1 = a.data;
    a.data = b.data;
    b.data = temp_1;

    int temp_2 = a.size;
    a.size = b.size;
    b.size = temp_2;

    temp_2 = a.capacity;
    a.capacity = b.capacity;
    b.capacity = temp_2;
}

//Constructors & Destructor
template<class T>
Stack<T>::Stack() : data(nullptr), capacity(0), size(0) {}
template<class T>
Stack<T>::Stack(int capacity_) : capacity(capacity_), size(0) 
{
    data = new T[capacity];
    if (!data)
        throw "ERROR - couldn't allocate memory\n";
}
template<class T>
Stack<T>::Stack(const Stack<T>& toCopy)
{
    size = 0;
    capacity = toCopy.capacity;
    data = new T[capacity];
    if (!data)
        throw "ERROR - couldn't allocate memory\n";

    for (int i = 0; i < toCopy.size; ++i, ++size)
        data[i] = toCopy.data[i];
}
template<class T>
Stack<T>::Stack(Stack<T>&& toMove)
{
    data = nullptr;
    size = capacity = 0;

    swap(*this, toMove);
}
template<class T>
Stack<T>::~Stack()
{
    clear();
}

//Methods
template<class T>
int Stack<T>::getSize() const
{
    return size;
}
template<class T>
int Stack<T>::getCapacity() const
{
    return capacity;
}
template<class T>
void Stack<T>::clear()
{
    if (data)
    {
        delete[] data;
        data = nullptr;
    }
    size = capacity = 0;
}
template <class T>
bool Stack<T>::isEmpty() const
{
    return size == 0;
}
template <class T>
bool Stack<T>::isFull() const
{
    return size == capacity;
}
template <class T>
T Stack<T>::pop()
{
    if (isEmpty())
        throw"Couldn't pop - Stack is empty\n";

    T toReturn = data[--size];
    T* temp = new T[capacity];
    if (!temp)
        throw "ERROR - couldn't allocate memory\n";
    for (int i = 0; i < size; i++)
        temp[i] = data[i];

    delete[]data;
    data = temp;
    
    return toReturn;
}
template <class T>
void Stack<T>::push(const T& toInsert)
{
    if (isFull())
        throw "Couldn't push - stack is full\n";

    T* temp = new T[capacity];
    if (!temp)
        throw "ERROR - couldn't allocate memory\n";
    for (int i = 0; i < size; i++)
        temp[i] = data[i];

    temp[size++] = toInsert;
    delete[]data;
    data = temp;
}
template<class T>
T Stack<T>::top() const
{
    if (isEmpty())
        throw"Couln't return top - Stack is empty\n";

    return data[size - 1];
}

//Operators
template<class T>
Stack<T>& Stack<T>::operator=(const Stack<T>& toAssign)
{
    if (data)
        delete[]data;

    Stack<T>help = toAssign;
    swap(*this,help);
    return *this;
}
template<class T>
Stack<T>& Stack<T>::operator=(Stack<T>&& toMove)
{
    if (data)
        delete[]data;

    data = nullptr;
    size = capacity = 0;
    
    swap(*this, toMove);
    return *this;
}

#endif

Код на GCC

template <class T>
class Stack
{
    //Inner class help
    void swap(Stack<T> &a, Stack<T>& b);

    T* data;
    int capacity;
    int size;
public:
    //Constructors & Destructor
    Stack();
    Stack(int capacity_);
    Stack(const Stack<T>& toCopy);
    Stack(Stack<T>&& toMove);
    ~Stack();

    //Methods
    int getCapacity() const;
    int getSize() const;
    void clear();
    bool isEmpty() const;
    bool isFull() const;
    T pop();
    void push(const T& toInsert);
    T top() const;

    //Operators
    Stack<T>& operator= (const Stack<T>& toAssign);
    Stack<T>& operator=(Stack<T>&& toMove);
};

//Inner class help
template<class T>
void Stack<T>::swap(Stack<T>& a, Stack<T>& b)
{
    T* temp_1 = a.data;
    a.data = b.data;
    b.data = temp_1;

    int temp_2 = a.size;
    a.size = b.size;
    b.size = temp_2;

    temp_2 = a.capacity;
    a.capacity = b.capacity;
    b.capacity = temp_2;
}

//Constructors & Destructor
template<class T>
Stack<T>::Stack() : data(nullptr), capacity(0), size(0) {}
template<class T>
Stack<T>::Stack(int capacity_) : capacity(capacity_), size(0) 
{
    data = new T[capacity];
    if (!data)
        throw "ERROR - couldn't allocate memory\n";
}
template<class T>
Stack<T>::Stack(const Stack<T>& toCopy)
{
    size = 0;
    capacity = toCopy.capacity;
    data = new T[capacity];
    if (!data)
        throw "ERROR - couldn't allocate memory\n";

    for (int i = 0; i < toCopy.size; ++i, ++size)
        data[i] = toCopy.data[i];
}
template<class T>
Stack<T>::Stack(Stack<T>&& toMove)
{
    data = nullptr;
    size = capacity = 0;

    swap(*this, toMove);
}
template<class T>
Stack<T>::~Stack()
{
    clear();
}

//Methods
template<class T>
int Stack<T>::getSize() const
{
    return size;
}
template<class T>
int Stack<T>::getCapacity() const
{
    return capacity;
}
template<class T>
void Stack<T>::clear()
{
    if (data)
    {
        delete[] data;
        data = nullptr;
    }
    size = capacity = 0;
}
template <class T>
bool Stack<T>::isEmpty() const
{
    return size == 0;
}
template <class T>
bool Stack<T>::isFull() const
{
    return size == capacity;
}
template <class T>
T Stack<T>::pop()
{
    if (isEmpty())
        throw"Couldn't pop - Stack is empty\n";

    T toReturn = data[--size];
    T* temp = new T[size];
    if (!temp)
        throw "ERROR - couldn't allocate memory\n";
    for (int i = 0; i < size; i++)
        temp[i] = data[i];

    delete[]data;
    data = temp;
    
    return toReturn;
}
template <class T>
void Stack<T>::push(const T& toInsert)
{
    if (isFull())
        throw "Couldn't push - stack is full\n";

    T* temp = new T[size + 1];
    if (!temp)
        throw "ERROR - couldn't allocate memory\n";
    for (int i = 0; i < size; i++)
        temp[i] = data[i];

    temp[size++] = toInsert;
    delete[]data;
    data = temp;
}
template<class T>
T Stack<T>::top() const
{
    if (isEmpty())
        throw"Couln't return top - Stack is empty\n";

    return data[size - 1];
}

//Operators
template<class T>
Stack<T>& Stack<T>::operator=(const Stack<T>& toAssign)
{
    if (data)
        delete[]data;

    Stack<T>help = toAssign;
    swap(*this,help);
    return *this;
}
template<class T>
Stack<T>& Stack<T>::operator=(Stack<T>&& toMove)
{
    if (data)
        delete[]data;

    data = nullptr;
    size = capacity = 0;
    
    swap(*this, toMove);
    return *this;
}

#include <iostream>
#include <string>
#include <cmath>

using namespace std;

bool operatorsPrecedenceCheck(string& str, Stack<char>& stk, const char& ch)
{
if (ch == '+' || ch == '-')
    {
        Stack<char> help(stk.getSize());
        char stkTop = '\0';
        if (!stk.isEmpty())
            stkTop = stk.top();
        while (!stk.isEmpty() && stkTop!='(') //Not mentioned but required
        {
            stkTop = stk.top();
            if (stk.top() == '*' || stk.top() == '/')
            {
                str += stk.pop();
                str += ' ';
            }
            else
                help.push(stk.pop());
        }
        while (!help.isEmpty())
            stk.push(help.pop());

        stk.push(ch);
        
        return 1;
    }
    else if (ch == '*' || ch == '/')
    {
        stk.push(ch);

        return 1;
    }
    

    return 0;
}
bool parenthesisCheck(string& str, Stack<char>& stk, const char& ch)
{
    if (ch == '(')
    {
        stk.push(ch);

        return 1;
    }
    else if (ch == ')')
    {
        while (stk.top() != '(')
        {
            str += stk.pop();
            str += ' ';
        }
        stk.pop();

        return 1;
    }

    return 0;
}

string infixToPostfix(const string &exp)
{
    string str = "";
    Stack<char> stk(exp.length());
    bool actionExecuted = 0;
    for (int i = 0; i < exp.length(); ++i)
    {
        actionExecuted = parenthesisCheck(str, stk, exp[i]);
        if (!actionExecuted)
            actionExecuted = operatorsPrecedenceCheck(str, stk, exp[i]);
        if (!actionExecuted)
        {
            if (exp[i] >= '0' && exp[i] <= '9')
            {
                for (; exp[i] >= '0' && exp[i] <= '9'; ++i)
                    str += exp[i];

                str += ' ';
                --i;
            }
            else
                throw"An illegal value in the expression\n";
        }
    }
    while (!stk.isEmpty())
    {
        str += stk.pop();
        str += ' ';
    }

    str = str.substr(0,str.length() - 1); //Cause of space

    return str;
}

int getValueFromString(const string& str, int &i)
{
    int result = 0;
    int amountOfDigits = 0;
    while (str[i+amountOfDigits] >= '0' && str[i+amountOfDigits] <= '9')
        ++amountOfDigits;

        for (int j = pow(10,amountOfDigits-1); j>=1; j /= 10)
            result += (str[i++] - '0') * j;
        --i;

    return result;
}

float calcPostfix(const string& str)
{
    Stack<int>stk(str.length()/2);
    for (int i = 0; i < str.length(); i += 2)
    {
        if (str[i] >= '0' && str[i] <= '9')
            stk.push(getValueFromString(str, i));
        else if (str[i] == '/')
            stk.push((float)1 / stk.pop() * stk.pop());
        else if (str[i] == '*')
            stk.push(stk.pop() * stk.pop());
        else if (str[i] == '+')
            stk.push(stk.pop() + stk.pop());
        else if (str[i] == '-')
            stk.push(-1 * (stk.pop() - stk.pop()));
        else
            throw"Unknown Operator in Calculating Postfix\n";
    }

    return stk.top();
}

int main()
{
    try
    {
        string exp;
        cout << "enter an infix expression as a string" << endl;
        cin >> exp;
        string postfix = infixToPostfix(exp);
        cout << postfix << endl;
        cout << calcPostfix(postfix) << endl;
    }
    catch (const char* exc)
    {
        cout << exc;
        exit(-1);
    }
    catch (...)
    {
        cout << "Unknown Error has occured\n";
        exit(-1);
    }

    return 0;
}

Я предлагаю исправить ваш код и предоставить правильный минимально воспроизводимый пример.

sweenish 06.06.2024 00:21

Я попытался написать программу на CPP, которая получает инфиксное выражение, преобразует его в постфиксное выражение и затем вычисляет это выражение. -- Если это ваша цель, почему бы не использовать std::stack вместо написания своего? Логику инфиксного -> постфиксного выражения все еще необходимо написать, но без необходимости микроуправления классами стека.

PaulMcKenzie 06.06.2024 00:23

@CSStudent — Если код работает «по-другому», значит, он вообще не работает.

PaulMcKenzie 06.06.2024 00:24

@PaulMcKenzie Потому что это обычное назначение структур данных? Учащимся необходимо написать стек, и им дается задание, в котором он используется. Если вы намерены поставить под сомнение логику профессора, спрашивать ОП — неправильный подход.

sweenish 06.06.2024 00:24

@CSStudent — В любом случае используйте std::stack при первом написании кода. Почему? Потому что, по всей вероятности, вы делаете со своим классом Stack что-то, что можно было бы легче обнаружить, если бы вы изначально использовали std::stack. Если вы используете Visual C++, среда выполнения отладки обнаружит ошибки такого типа. Как только вы получите код, работающий с std::stack, снова представьте самодельный класс стека.

PaulMcKenzie 06.06.2024 00:27

@CSStudent — Если такой простой код дает два разных результата от двух разных компиляторов, то в 99,9% случаев код неисправен.

PaulMcKenzie 06.06.2024 00:28

Причиной обычно является неопределенное поведение: https://stackoverflow.com/questions/367633/what-are-all-the-‌​common-undefined-beh‌​aviours-that-a-c-pro‌​grammer-should-know -‌​а

drescherjm 06.06.2024 00:33

@CSStudent - Я предлагаю вам придерживаться g++ и заставить его работать, поскольку вы знаете, что можете воспроизвести там испорченные результаты. Как только вы заставите его работать с внесенными вами изменениями, внесите те же изменения для Visual C++. Кроме того, я не знаю, написал ли ваш учитель класс Stack, но есть одно предложение — не возвращать pop никакого значения. Это сделает класс Stack более похожим на std::stack. Другими словами, если вам нужно верхнее значение в стеке, вы должны вызвать top(), чтобы получить его.

PaulMcKenzie 06.06.2024 00:40

Более простой способ написать стек — обернуть другую структуру, например вектор или связанный список. По крайней мере, когда я преподавал, стопка и очередь были простыми домашними заданиями. Связанный список из предыдущего задания был тщательно протестирован, и стек просто обернул его. Тогда во всей этой isFull() ерунде нет необходимости. Совет по использованию std::stack позволит вам тщательно протестировать ваш инфиксно->постфиксный код. Как только все будет готово, вы сможете вернуть свой собственный стек и устранить неполадки в нем. Всегда нужно разбить все на управляемые части.

sweenish 06.06.2024 00:42

@CSStudent — Что, если все, что я хочу сделать, это сохранить popping и не заботиться о возвращаемом значении? Ваш код неэффективен, поскольку pop всегда будет возвращать копию значения, а копирование может быть дорогостоящим, если тип, хранящийся в Stack, имеет дорогостоящую операцию копирования. C++ создан для повышения эффективности, и если мне нужно максимальное значение, я явно попрошу об этом, позвонив top. Еще одно различие между вашим классом и std::stack заключается в том, что top() возвращает ссылку на std::stack::top, а не копию значения.

PaulMcKenzie 06.06.2024 00:54

И я не использовал связанные списки или вектор, потому что это для следующего задания.

CS Student 06.06.2024 00:55

Ниндзя на пенсии — я обновил код примерно через 1 минуту после того, как опубликовал эту проблему. Это действительно странно. ты!

CS Student 06.06.2024 00:58

@PaulMcKenzie - После этого назначения мы должны научиться использовать std::stack, поэтому мы узнали, как использовать стек и неясно, как он реализуется. Но спасибо за предложения. Думаю, мне следует написать свой собственный стек, более похожий на std::stack. Подробности я посмотрю позже.

CS Student 06.06.2024 01:02

@sweenish -- Спасибо, ты был прав, проблема в моем стеке. Завтра еще раз посмотрю. Спасибо вам всем!

CS Student 06.06.2024 01:20

@CSStudent - Похоже, проблема в вычитании. Перепишите вычитание так, как указано: сохраните верхнее значение во временном файле, затем извлеките его, затем сохраните верхнее значение в другом временном файле и извлеките его. Затем выполните вычитание, используя временные символы, вместо двух вызовов pop в одной строке.

PaulMcKenzie 06.06.2024 01:30

Это может быть актуально. Я считаю, что проблема в том, что вы меняете стек несколько раз в одной логической строке кода, и не указан порядок, какой pop будет выполнен первым. Побочным результатом написания pop, чтобы не возвращать значение, было бы то, что вам пришлось бы сделать два (или более) явных вызова top, а затем pop, что сделало бы порядок вычитания четко определенным. Так что да, ваш класс стека ошибочен, но в каком-то смысле вы этого не осознавали.

PaulMcKenzie 06.06.2024 01:40

Пройдя через это самостоятельно и протестировав, вы должны написать ответ, действительно ли изменение класса Stack дает правильные результаты (так и должно быть).

PaulMcKenzie 06.06.2024 01:42
else if (str[i] == '-') stk.push(-1 * (stk.pop() - stk.pop())); -- Точнее, похоже, виноват именно этот код.
PaulMcKenzie 06.06.2024 02:43

«Итак, мой вопрос: знает ли кто-нибудь, что может вызвать эту разницу? Может быть, в компиляторах что-то другое?» - Первое правило программирования: всегда твоя вина. См. также Что такое отладчик и как он может помочь мне диагностировать проблемы? и Неопределенное поведение.

Jesper Juhl 06.06.2024 11:15

@PaulMcKenzie -- Огромное спасибо! Раньше я не знал о «Порядке оценок», и это очень полезно, и теперь все это имеет смысл. Сейчас я поработаю со стеком, но просто хочу спросить, не ошибаюсь ли я, говоря, что строка else if (str[i] == '/') stk.push((float)1 / stk.pop() * stk.pop()); тоже ошибочна

CS Student 06.06.2024 11:22

да, в этой строке присутствует та же проблема (см. мой ответ), она работает в msvc, gcc и clang, но нет гарантии, что она будет такой же в других компиляторах или даже в будущих версиях этих компиляторов.

Alan Birtles 06.06.2024 11:32

@JesperJuhl -- Спасибо, я прочту то, что актуально

CS Student 06.06.2024 11:42

@PaulMcKenzie — Могу ли я спросить, почему top() возвращает ссылку?

CS Student 06.06.2024 19:04

@CSStudent — ссылка возвращается для повышения эффективности, а также позволяет пользователю напрямую изменять верхнее значение. Если пользователю std::stack действительно нужна копия, он может сделать это явно для std::stack<T> theStack;, используя T val = theStack.top();, в противном случае T& val = theStack.top(); предоставит ссылку.

PaulMcKenzie 06.06.2024 19:51

Большое спасибо @PaulMcKenzie, ты мне очень помог! Кстати, я только что получил 100 за задание. Спасибо!

CS Student 06.06.2024 23:46
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
25
146
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В stk.pop() - stk.pop() нет никакой гарантии, что левая рука pop() произойдет первой, если вы измените на:

auto a = stk.pop();
auto b = stk.pop();
stk.push(-1 * (a - b));

Вы получите одинаковое поведение в разных компиляторах.

У вас та же проблема в (float)1 / stk.pop() * stk.pop().

Ваш исходный код с добавленной отладкой: https://godbolt.org/z/xEKzeTzvn

Исправленная версия: https://godbolt.org/z/oczef5hrj

Спасибо! Но у меня возникло несколько вопросов: во-первых, почему вы использовали auto в функции CalcPostfix? CalcPostfix вычисляет выражение, имеющее целые числа. Во-вторых, цель дополнительной отладки — позволить вам увидеть размер стека и функцию top() в каждой строке? А если это так, то зачем вам печатать размер стека и функцию top(), а не что-то еще? В-третьих, почему вы изменили \n в строках 337 (throw"Unknown Operator in Calculating Postfix\\n";) и 362 (cout << "Unknown Error has occured\\n";)?

CS Student 06.06.2024 12:26

Почему бы не использовать auto? это избавляет меня от необходимости искать типы данных. Не уверен, о чем вы спрашиваете в своем втором вопросе, я просто напечатал несколько значений, чтобы вы могли увидеть, где поведение компиляторов различается. Я не менял строку, я просто скопировал исходный код из вопроса.

Alan Birtles 06.06.2024 13:48

Хорошо, я попытаюсь задать более ясный вопрос: зачем вам распечатывать информацию, которую вы напечатали, особенно там, где вы ее распечатали. а не где-нибудь еще в коде? И почему вы печатаете эту информацию, а не другую информацию?

CS Student 06.06.2024 15:24

@CSStudent, потому что именно эта информация используется на данном этапе программы и показывает, где что-то пошло не так.

Alan Birtles 06.06.2024 15:56

Да, но вы решили распечатать там информацию для обнаружения ошибки? Или за то, что показал мне это?

CS Student 06.06.2024 15:58

Чтобы найти ошибку, сравнив выходные данные, я увидел, где программа расходится между clang и gcc. Конечно, лучше использовать отладчик, чем печатать значения.

Alan Birtles 06.06.2024 16:14

Вы могли бы сказать, где программа расходится между clang и gcc, напечатав там значения, но вы не могли знать, что печать там значений приведет к обнаружению точки отклонения. Следовательно, как вы печатали значения именно там, где возникает проблема? Это была чистая удача?

CS Student 06.06.2024 18:22

@CSStudent — Это не чистая удача. Суть в том, что вы знаете, что в какой-то момент помещаете что-то в стек. Вы берете те критические точки, где вы это делаете, и записываете, что происходит. Это навык, который вам понадобится как программисту. Это не просто «Я знаю, что ошибка здесь, поэтому позвольте мне записать все», нет, это не лучший подход к этому. Вы записываете все моменты, когда ваша программа может пойти не так. Метод, который использовал АланБиртлес, — это тот, который я использовал, чтобы увидеть, что вычитание было ошибочным, и заключается в регистрации того, что помещалось в стек.

PaulMcKenzie 06.06.2024 19:53

Постфиксная строка была одинаковой для обоих компиляторов, поэтому проблема должна была быть в calcPostfix, тогда я просто инструментировал всю функцию.

Alan Birtles 06.06.2024 22:20

Хорошо, спасибо. Кстати, я только что закончил и получил 100. Огромное спасибо!

CS Student 06.06.2024 23:45

Спасибо @PaulMcKenzie, я спросил то, что просил, чтобы лучше узнать, как достичь этого навыка.

CS Student 06.06.2024 23:48

Кстати, последнее: в следующем коде я получаю предупреждение C6011. const char *stkTop = nullptr; if (!stk.isEmpty()) stkTop = &stk.top(); while (!stk.isEmpty() && *stkTop!='(') {} Получаю ли я предупреждение, потому что он не знает, равен ли &stk.top() значению nullptr?

CS Student 07.06.2024 00:09

Предупреждение, вероятно, выдается потому, что вы условно устанавливаете stkTop в операторе if, поэтому возможно, что stkTop все еще остается nullptr, когда выполняется цикл while.

PaulMcKenzie 07.06.2024 02:10

@PaulMcKenzie — Да, но он назначает stkTop=&stk.top(); if (!stk.isEmpty). И в цикле while это будет работать *stkTop!='(' только в том случае, если !stk.isEmpty). Следовательно, он будет разыменовывать stkTop только в том случае, если !stk.isEmpty, а если ``!stk.isEmpty`, это означает, что stkTop уже назначен с помощью &stk.top() .

CS Student 08.06.2024 20:36

Компилятор знает только то, что происходит во время компиляции. Он не смотрит на то, что произойдет во время выполнения. То же самое: int foo(int x) { if (x > 0 && x <= 100) return 1; else if (x >100) return 2; } и предупреждение о том, что не все пути возвращают значение, хотя во время выполнения вы вызываете foo(1);.

PaulMcKenzie 08.06.2024 20:40

Компилятор может определить, что stk.isEmpty() не меняется между двумя его вызовами и, следовательно, stkTop всегда будет присваиваться, но это, вероятно, более глубокий анализ, чем большинство компиляторов, самый простой способ отключить предупреждение - переместить while в тело оператора if, это может даже сделать ваш код немного более эффективным.

Alan Birtles 09.06.2024 00:23

@AlanBirtles - Спасибо, теперь я понял концепцию. Спасибо и за подсказку.

CS Student 10.06.2024 16:18

Другие вопросы по теме

В VS 2022 появляется сообщение «Горячая перезагрузка — изменения не поддерживаются», но я ничего не менял
Не могу создать свое приложение .NET 8 Maui в эмуляторе iOS
«В DLL нет компонентов, которые можно было бы разместить на панели инструментов» произойдет в 2022 году
Расширение Intellisense в ReSharper 2024.1.2 для Visual Studio 2022 иногда может перестать предлагать предложения при нажатии Ctrl + J (C#)
Импортировать блок заголовка std в файл реализации модуля
Как установить описание файла приложения на C# (.NET 8)?
Есть ли способ обновить версию C# в Visual Studio до 12.0 при использовании платформы .NET?
Невозможно распространить приложение MAUI iOS в магазине приложений VS2022. Задаче «CompileAppManifest» не было присвоено значение обязательного параметра «DefaultSdkVersion»
Как я могу использовать gocv в Go с поддержкой CUDA в Windows 11?
Как просматривать файлы на эмуляторе Android в Visual Studio (MAUI), аналогично «Проводнику устройств» в студии Android?