Директивы препроцессора
Добро пожаловать на блог ojgen-it. Для первого поста я выбрал совершенно случайную тему. Это Директивы препроцессора.
Сегодня я создам маленькую программу, которая демонстрирует работу с #define. Думаю, нет особого смысла здесь, что-либо рассказывать о препроцессоре. На википедии и так хорошее описание.
Наша программка будет фильтровать символы, введенные с клавиатуры, меняя их на звездочки. Чтобы было интереснее - добавлю меню, в котором можно будет выбрать, что именно фильтровать, текст или цифры, например. Итак, приступим.
Для начала напишем код, который позволит вводить символы с клавиатуры:
#include <iostream>
#include <conio.h>
#include <windows.h>
using namespace std;
int main() {
int i=0;
char ch=0;
char str[256];
while (true) {
system("cls");
for(int j=0; j < i; j++) {
cout << str[j];
}
str[i++] = _getch();
}
return 0;
}
- system("cls"); - с помощью этой функции можно очистить консоль;
- _getch(); - эта функция ожидает нажатия клавиши, и возвращает ее код в int. Для использования функции нужно подключить библиотеку conio.h.
Теперь добавим больше функциональности примеру, и заодно используем #define для определения констант:
#include <iostream>
…
#define ENDLINE '\n' // «;» после директив ставить не нужно
int main() {
int i=0;
char ch=0;
char str[256];
while (true) {
system("cls");
for(int j=0; j < i; j++)
cout << str[j];
ch = _getch();
switch (ch) {
case 83: // клавиша del
for (int j=0; j < i; str[j++] = ' ');
i=0;
break;
case 8: // клавиша backspace
if (i > 0)
str[--i] = ' ';
break;
case 13: // клавиша enter
str[i++] = ENDLINE;
break;
default :
str[i++] = ch;
break;
}
}
return 0;
}
При нажатии на любую клавишу ми получаем ее код, и можем делать то или иное действие. Вы можете сами посмотреть нужный вам код клавиши, просто посмотрев результат _getch(), или найти уже составленные таблицы, например, здесь.
Я объявил текстовую константу ENDLINE – теперь, при нажатии на Enter, в массив str будет дописан символ нового рядка. Ми сможем перейти на новую строчку и набирать текст дальше. Также при нажатии Backspace, можно «стирать» последний символ, или все символы, нажав на Del. Все другое будет, записывается в массив str.
Создадим еще одну константу и макросы:
#include <iostream>
…
#define FILTER '*'
// таблицу ASCII кодов можно найти по силке выше
#define UP_LATIN(ch) ( ch > 65 && ch < 90 )
#define LO_LATIN(ch) ( ch > 97 && ch < 122 )
#define FILTER_LATIN(ch) ( (UP_LATIN(ch) || LO_LATIN(ch)) ? FILTER : ch )
#define FILTER_CYRILLIC(ch) ( (ch > 191 && ch < 256) ? FILTER : ch )
#define FILTER_NUMBER(ch) ( ch > 47 && ch < 58 ? FILTER : ch )
int main() { … }
Используем эти макросы и добавим меню:
int main() {
int i=0;
int choice = 0, size=3;
char ch=0;
char str[256];
char * menu[] = { "No filtering", "Latin characters filter", "Number filter"};
while (true) {
system("cls");
for (int j = 0; j < size; j++) {
cout << ( choice==j ? " >> " : " ") << menu[j] << ( j==0 ? ENDLINE : ' ' ) << endl;
}
cout << endl << endl;
for (int j=0; j < i; j++) {
switch(choice) {
case 0:
cout << str[j];
break;
case 1:
cout << FILTER_LATIN(str[j]);
break;
case 2:
cout << FILTER_NUMBER(str[j]);
break;
}
}
ch = _getch();
switch (ch) {
case -32:
break;
case 72: // стрелка вверх
if (choice != 0)
choice--;
break;
case 80: // стрелка вниз
if (choice != size - 1)
choice++;
break;
. . .
}
}
return 0;
}
Теперь, ми можем вводить и удалять текст, а параллельно, стрелками вверх/вниз менять способ фильтрации текста.
Может быть вы обратили внимание на код
case -32: break;
, в самом начале switch. Если вы его закомментируйте и посмотрите результат, то обнаружите, что при нажатии стрелки вверх/вниз, помимо смены режима фильтрации, в текст добавится символ «p».
Почему так происходит?
Все дело в том, что при нажатии на определенные клавиши (стрелки входят в их число), код возвращается два раза. Таким способом первый код отлавливается.