Символы перекрываются, когда они изменили цвет и напечатаны задом наперед

Как вы можете видеть, верхние темные X вырезаны, хотя для них есть место.

Это происходит потому, что они изменили цвет и печатаются в обратном направлении (справа налево).

Это ошибка, неисправный код, плохая настройка в моей системе или (я сомневаюсь в этом), как это должно быть?

Вот код, который генерирует этот вывод:

#include <Windows.h>
#include <iostream>
void moveTo(int x,int y){
    COORD kord={x,y};
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),kord);
}
void setColor(WORD attributes){
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), attributes);
}

void main(){
    for(int i=9;i+1;i--)
    {
        moveTo(i,0);
        std::cout.put('X');
    }
    for(int i=-10;i;i++)
    {
        moveTo(i+10,1);
        std::cout.put('X');
    }
    setColor(8);
    for(int i=9;i+1;i--)
    {
        moveTo(i,2);
        std::cout.put('X');
    }
    for(int i=-10;i;i++)
    {
        moveTo(i+10,3);
        std::cout.put('X');
    }
    setColor(7);
    for(int i=9;i+1;i--)
    {
        moveTo(i,4);
        std::cout.put('X');
    }
    for(int i=-10;i;i++)
    {
        moveTo(i+10,5);
        std::cout.put('X');
    }
    std::cin.get();
}

1 ответ

Решение

Это ошибка в Windows.

Как упоминалось в сообщении Hans Passant:

Я тоже репро, VS2008 на Win7. Классный баг. Изменение шрифта консоли исправляет это.

Давайте использовать эту изоляцию от ошибок. Я распознаю этот шрифт как Petite Terminal, что подразумевает, что вы, скорее всего, настроили этот проект как консольное приложение Win32. Дополнительная репродукция с GCC подтверждает эту гипотезу, и мы предположим, с практической точки зрения, что все вы получали 32-битное консольное приложение, работающее внутри терминала Windows.

Возникает вопрос, почему он записывает ровно один дополнительный столбец пикселей в контексте шрифта терминала по умолчанию, цвет 8, и обратно, записывая в буфер экрана консоли.

В частности, давайте разберем эту проблему на составные части:

  1. Когда выдается запись, символ записывается в местоположение в терминальном массиве.
  2. Когда выбран цвет по умолчанию (7), пиксели не переполняются в другие буферы в массиве
  3. Когда выбран цвет 8, дополнительный столбец пикселей записывается в следующую область буфера, которая видна только тогда, когда текст читается в обратном направлении.

Из-за наличия переполнения в (3), это ошибка.

Цитируя Рэймонда Чена:

Модель рендеринга консоли предполагает, что каждый символ аккуратно вписывается в ячейку фиксированного размера. Когда новый символ записывается в ячейку, старая ячейка печатается с новым символом, но если старый символ имеет вылет или подвисание, эти дополнительные пиксели остаются позади, так как они "пролились" на требуемую ячейку и зараженные соседние ячейки. Точно так же, если соседний символ "перетек", эти "побочные пиксели" будут стерты.

Набор шрифтов, которые можно использовать в окне консоли, был обрезан до шрифтов, которые были протестированы и, как известно, приемлемо работают в окнах консоли. Для английских систем это привело нас к Lucida Console и Terminal.

...

"Ну, это глупо. Ты должен был помешать мне выбрать шрифт, который так явно приводит к бессмыслице".

И это то, что мы сделали.

Не то чтобы я обвинял Рэймонда в этом, но он авторитетно иллюстрирует это как "не может случиться".

Выбор и тестирование консольных шрифтов для Windows должны были это поймать. Тот факт, что это вообще проблема, является отклонением.

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