Как насчет этого?
std::string getstring()
{
std::string input;
// let the terminal do the line editing
nocbreak();
echo();
// this reads from buffer after <ENTER>, not "raw"
// so any backspacing etc. has already been taken care of
int ch = getch();
while ( ch != '\n' )
{
input.push_back( ch );
ch = getch();
}
// restore your cbreak / echo settings here
return input;
}
Я бы отказался от использования альтернативного семейства функций *scanw()
. Вы будете манипулировать временным буфером char []
, базой *scanf()
со всеми его проблемами, плюс спецификация *scanw()
утверждает, что он возвращает ERR
или OK
вместо количества проверенных элементов, что еще больше уменьшает полезность.
Хотя getstr()
(предложенный пользователем indiv) выглядит лучше, чем *scanw()
и выполняет специальную обработку функциональных клавиш, для него все равно потребуется временное char []
, и я стараюсь избегать C ++, если ничего, кроме как избежать произвольного размера буфера.
Я также сталкивался с этой проблемой при программировании для микроконтроллеров AVR. Avr-libc имеет заголовочные файлы (включенный до <avr/io.h>
, которые делают доступными расположение регистра для каждого микроконтроллера путем определения макросы такой как [1 113]:
#define TCNT1 (*(volatile uint16_t *)(0x84))
Это позволяет использовать TCNT1
, как будто это была нормальная переменная и любые чтения, и записи направлены к адресу памяти 0x84 автоматически. Однако это также включает (неявный) reinterpret_cast
, который предотвращает использование адреса этой "переменной" в константном выражении. И так как этот макрос определяется avr-libc, изменение его для удаления броска не является действительно опцией (и переопределение таких макросов самостоятельно работает, но тогда требует определения их для всех различных микросхем AVR, копируя информацию от avr-libc).
, Так как складной взлом, предложенный Shafik здесь, кажется, больше не работает в gcc 7 и выше, я искал другое решение.
Рассмотрение avr-libc заголовочных файлов более тесно, оказывается, что у них есть два режима : - обычно, они определяют подобные переменной макросы как показано выше. - При использовании в ассемблере (или при включении с _SFR_ASM_COMPAT
определенный), они определяют макросы, которые просто содержат адрес, например: #define TCNT1 (0x84)
На первый взгляд последний кажется полезным, так как Вы могли тогда установить _SFR_ASM_COMPAT
, прежде чем будут включать <avr/io.h>
и просто будут использовать intptr_t
константы и использовать адрес непосредственно, а не через указатель. Однако, так как можно включать avr-libc заголовок только однажды (iow, только имейте TCNT1
или как переменная как макрос или как адрес), этот прием только работает в исходном файле, который не включает никакие другие файлы, которым была бы нужна переменная как макросы. На практике это кажется маловероятным (хотя, возможно, у Вас мог быть constexpr (класс?) переменные, которые объявлены в.h файле и присвоены значение в .cpp файле, который не включает ничто иное?).
В любом случае, я нашел другой прием Krister Walfridsson , который определяет эти регистры как внешние переменные в заголовочном файле C++ и затем определяет их и определяет местоположение их в фиксированном местоположении при помощи ассемблера.S файл. Тогда можно просто взять адрес этих глобальных символов, который допустим в constexpr выражения. Для создания этой работы этот глобальный символ должен иметь другое имя как исходный макрос регистра, для предотвращения конфликта между обоими.
, Например, в Вашем коде C++, Вы имели бы:
extern volatile uint16_t TCNT1_SYMBOL;
struct foo {
static constexpr volatile uint16_t* ptr = &TCNT1_SYMBOL;
};
И затем Вы включаете.S файл в свой проект, который содержит:
#include <avr/io.h>
.global TCNT1_SYMBOL
TCNT1_SYMBOL = TCNT1
При записи этого, я понял, что вышеупомянутое не ограничено случаем AVR-libc, но может также быть применено к более универсальному вопросу, который задают здесь. В этом случае Вы могли получить файл C++, который похож:
extern char MY_PTR_SYMBOL;
struct foo {
static constexpr const void* ptr = &MY_PTR_SYMBOL;
};
auto main() -> int {
return 0;
}
И.S файл, который похож:
.global MY_PTR_SYMBOL
MY_PTR_SYMBOL = 0x1
Вот то, как это смотрит: https://godbolt.org/z/vAfaS6 (я не мог выяснить, как заставить проводник компилятора связывать и cpp и.S файл вместе, хотя
Этот подход имеет вполне немного больше шаблона, но, действительно кажется, работает надежно через версии лязга и gcc. Обратите внимание, что этот подход похож на аналогичный подход с помощью параметров командной строки компоновщика или сценариев компоновщика для размещения символов в определенном адресе памяти, но тот подход является очень непортативным и хитрым для интеграции в процессе сборки, в то время как подход, предложенный выше, является более портативным и просто вопрос добавления.S файла в сборку.