Почему символ преобразуется в цифру при использовании toupper?

крошечный.ч

#ifndef _TINYC_H
#define _TINYC_H

#include <string>
#include <vector>
#include <map>

namespace tinyc {

using token_t = std::map<std::string, std::string>;
using tokens_t = std::vector<token_t>;

// const std::string DIGITS = "0123456789";
// const std::string WHITESPACE = " \t\n";
    
tokens_t tokenize(const std::string& str);
void print_tokens(const tokens_t& tokens);

} // namespace tinyc

#endif // _TINYC_H

main.cpp

#include <iostream>
#include "tinyc.h"

int main() {
    tinyc::tokens_t tokens;

    try {
        tokens = tinyc::tokenize("()");
    } catch (const std::string& e) {
        std::cerr << e << '\n';
    }

    tinyc::print_tokens(tokens);
}

Это весь код.

В этой части кода в tinyc.h:

void print_tokens(const tokens_t& tokens) {
    if (!tokens.empty()) {
        for (const token_t& token : tokens) {
            for (const auto& token_pair : token) { // std::pair<...>
                for (const char& c : token_pair.first) { // token_pair.first = std::string
                    std::cout << ::toupper(static_cast<unsigned char>(c));
                }
                std::cout << ':' << token_pair.second << '\n';
            }
        }
    }
}

Внутри этой части вот это:

std::cout << ::toupper(static_cast<unsigned char>(c)); // Prints random digits. No idea why!? Changed toupper to tolower, un-typecasted it, etc, but nothing worked.

Печатает случайные цифры. Понятия не имею почему. Я изменил toupper на tolower, не применял тип и т. д., но ничего не работало.

Но по какой-то причине этот код ниже работает отлично:

std::cout << c;

Этот код ниже, std::cout << c, отлично работает и печатает фактические символы, а не случайные цифры.

Я также пробовал (c & ~32) в верхнем регистре, но тот же результат, он печатает случайные цифры.

            tokens.push_back({
                { "type", "rparen" },
                { "value", ")" }
            });

Вот как я вставляю карту в вектор; я делаю это неправильно? Это то, что вызывает проблему?

Почему это печатает случайные цифры, когда должно печатать символы?


person Jack Murrow    schedule 17.12.2020    source источник
comment
Разве вы не можете избавиться от большей части этого кода и по-прежнему воспроизводить ошибку? Посмотрите, как создать минимально воспроизводимый пример, и, в частности, прочитайте минимальную часть.   -  person cigien    schedule 17.12.2020
comment
Возможно, вы захотите ознакомиться с Как задать вопрос, в частности, с описанием проблемы перед публикацией кода (и часть о достаточном количестве кода, чтобы другие могли воспроизвести проблему, но cigien уже упоминал об этом).   -  person JaMiT    schedule 17.12.2020
comment
toupper возвращает int, поэтому, хотя он должен возвращать правильное значение, тип заставляет его распечатываться в десятичном виде, а не в виде символа. Вы можете вернуть его к char перед печатью.   -  person Nate Eldredge    schedule 17.12.2020
comment
toupper возвращает int. Если вы хотите напечатать его как char, вам нужно привести результат. en.cppreference.com/w/cpp/string/byte/toupper   -  person Retired Ninja    schedule 17.12.2020
comment
@cigien Я уменьшил количество кода.   -  person Jack Murrow    schedule 17.12.2020
comment
@NateEldredge Это было бы точно так же, как и любое другое обычное приведение типов для печати в виде символа справа: std::cout << static_cast<char>(::toupper(static_cast<unsigned char>(c)));   -  person Jack Murrow    schedule 17.12.2020
comment
Это не случайные цифры, если посмотреть на число и найти его в таблице ASCII вы могли бы понять лучше.   -  person Mark Ransom    schedule 17.12.2020
comment
@JackMurrow Код все еще выглядит длинным. Строка, о которой вы спрашиваете, std::cout << ::toupper(static_cast<unsigned char>(c));. Минимальная функция main, обеспечивающая синтаксическую работу этой строки, — это int main() { const char c = 'a'; std::cout << ::toupper(static_cast<unsigned char>(c)); }. Насколько близко к этому минимальному синтаксису вы можете вести свой пример, сохраняя при этом сомнительное поведение?   -  person JaMiT    schedule 17.12.2020
comment
Спасибо за редактирование вопроса. Однако, как отмечают другие пользователи, кода по-прежнему больше, чем нужно для решения проблемы, с которой вы столкнулись. Попробуйте удалить как можно больше, сохраняя при этом поведение, которое вас смущает. Это требует некоторой практики, но поможет несколькими способами: 1) Возможно, вы сможете определить проблему самостоятельно. 2) Даже если вы этого не сделаете, другие пользователи заметят проблему быстрее, когда им не придется читать много несвязанного кода.   -  person cigien    schedule 17.12.2020
comment
@MarkRansom Да, теперь я понял, что это ASCII, но поначалу трудно понять, когда все, что вы видите, похоже на 8238924982 в выводе, поэтому они появлялись как случайные цифры.   -  person Jack Murrow    schedule 17.12.2020
comment
@JackMurrow Похоже, вы обнаружили один из способов, которым может помочь минимальный пример. В частности, если бы вы попытались вывести только один символ, а не набор символов, следующих друг за другом, было бы легче заметить, что результатом является ASCII. ;)   -  person JaMiT    schedule 18.12.2020


Ответы (1)


Функция int toupper( int ch ); унаследована от C, поэтому возвращает int. Чтобы правильно печатать, вам нужно привести тип обратно к char:

std::cout << static_cast<char>(::toupper(static_cast<unsigned char>(c)));
person Eugene    schedule 17.12.2020
comment
Он должен принимать EOF, который является целочисленной константой, поэтому он возвращает int. - person john; 17.12.2020
comment
@john Oha: std::toupper() Если значение ch не может быть представлено как unsigned char и не равно EOF, поведение не определено. Просто узнайте что-то новое... :-) - person Scheff's Cat; 17.12.2020