0

tinyc.h

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

This is the whole code.

In this part of the code in 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';
            }
        }
    }
}

Inside this part, this here:

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.

Prints random digits. I have no idea why. I changed toupper to tolower, didn't typecast it, etc, but nothing worked.

But for some reason, this code below works perfectly fine:

std::cout << c;

This code below, std::cout << c, works perfectly fine and prints the actual characters, not any random digits.

I've also tried (c & ~32) to upper case it but same results, it prints random digits.

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

This is how I insert a map in the vector; am I doing this wrong? Is this what causes the issue?

Why is this printing random digits when it should be printing characters?

Jack Murrow
  • 396
  • 3
  • 11
  • 3
    Can't you get rid of most of this code and still reproduce the error? Please see how to make a [mre], and read the "minimal" part in particular. – cigien Dec 17 '20 at 04:10
  • You might want to review [ask], in particular the part about introducing the problem before posting any code (and the part about "just enough code to allow others to reproduce the problem", but cigien already mentioned that). – JaMiT Dec 17 '20 at 04:13
  • 3
    `toupper` returns `int`, so while it should be returning the right value, the type causes it to be printed out in decimal instead of as a character. You could cast it back to `char` before printing. – Nate Eldredge Dec 17 '20 at 04:14
  • `toupper` returns an `int`. If you want to print it as a `char` you'll need to cast the result. https://en.cppreference.com/w/cpp/string/byte/toupper – Retired Ninja Dec 17 '20 at 04:14
  • @cigien I've lessened the amount of code. – Jack Murrow Dec 17 '20 at 04:15
  • 1
    @NateEldredge It would be just like any other usual typecast for printing it as a char right: `std::cout << static_cast(::toupper(static_cast(c)));` – Jack Murrow Dec 17 '20 at 04:17
  • Those aren't random digits, if you looked at the number and looked it up on an [ASCII table](https://en.wikipedia.org/wiki/ASCII#Printable_characters) you might understand better. – Mark Ransom Dec 17 '20 at 04:26
  • 1
    @JackMurrow The code still looks long. The line you qustion is `std::cout << ::toupper(static_cast(c));`. A minimal `main` function to make that line work syntactically is `int main() { const char c = 'a'; std::cout << ::toupper(static_cast(c)); }`. How close to this minimal syntax can you drive your example while retaining the questioned behavior? – JaMiT Dec 17 '20 at 04:27
  • 1
    Thank you for editing the question. However, as pointed out by other users there is still more code than is relevant to the problem you're facing. Try and remove as much as possible while still preserving the behavior that you're confused by. This takes some practice but will help in multiple ways: 1) You might be able to identify the problem yourself. 2) Even if you don't, other users will spot the problem faster when they don't have to read lots of unrelated code. – cigien Dec 17 '20 at 04:43
  • @MarkRansom Yes, I now realized those were ASCII, but at first it's hard to realize when all you see is like `8238924982` in the output, so they **appeared** as random digits. – Jack Murrow Dec 17 '20 at 05:10
  • @JackMurrow Looks like you've discovered one way a minimal example can help. Specifically, if you had tried to output only a single character -- instead of a bunch of characters right after each other -- it might have been easier to notice that the result is ASCII. ;) – JaMiT Dec 18 '20 at 18:22

1 Answers1

3

Function int toupper( int ch ); is inherited from C, so it returns int. To print properly, you need to typecast back to char:

std::cout << static_cast<char>(::toupper(static_cast<unsigned char>(c)));
Jack Murrow
  • 396
  • 3
  • 11
Eugene
  • 6,194
  • 1
  • 20
  • 31
  • 1
    It has to accept `EOF` which is an integral constant, that's why it returns an `int`. – john Dec 17 '20 at 06:10
  • @john Oha: [std::toupper()](https://en.cppreference.com/w/cpp/string/byte/toupper) _If the value of ch is not representable as unsigned char and does not equal EOF, the behavior is undefined._ Just have something new learnt... :-) – Scheff's Cat Dec 17 '20 at 06:44