经过前面几篇文章的铺垫,完成了C语言接口层的GPIO、外部中断、串口、delay等接口,现在可以正式进入C++驱动层的文章。当然C语言接口层的还远没有完成,在以后的文章中还会继续更新。
本文将会介绍一个C++驱动层中非常重要的两个类,outputStream和inputStream,作为输入输出流的基类,为单片机的数据输出提供了统一的接口。在以后的文章中会介绍到的硬件串口类 HardwareUART类和移植的Adafruit的图形类Adafruit_GFX类等都是继承这个类的派生类。这两个类主要参考了Arduino的Print类和Stream类,并进行了修改和扩展。可以满足多种风格的输入输出。
一、从Arduino的串口输入输出函数分析输入输出类:
有使用过Arduino的大佬应该对Arduino的输入输出函数很熟悉,先举几个栗子
1.Arduino的串口输入输出函数
Serial.print("hello world");
Serial.println("hello wrold");
char* str="hello world";
Serial.write(str, strlen(str));
char c;
if(Serial.available())
c=Serial.read();
......
2.ESP32/8266 TCP服务器或客户端的输入输出函数
client.print("hello world");
client.println("hello wrold");
char* str="hello world";
client.write(str, strlen(str));
char c;
if(client.available())
c=client.read();
3.Adafruit的OLED库打印字符
display.println("hello wrold");
display.display();
这三个栗子分别操作不同的硬件,而调用的函数却都是一样的print、println、write等。我们再来看看这几个对象的所对应的类:
1.Arduino的串口Serial:
Arduino的串口Serial是类HardwareSerial的实例化对象,这个类的定义和声明可以在arduino安装目录下的hardware\arduino\avr\cores\arduino中找到
class HardwareSerial : public Stream
2.服务器或客户端的输入输出函数
以客户端为例,client对象是类Client的实例化对象,这个类的声明也可以在arduino安装目录下的hardware\arduino\avr\cores\arduino中找到
class Client : public Stream
3.Adafruit的OLED
oled对象是类Adafruit_SSD1306的实例化对象,Adafruit_SSD1306继承自类Adafruit_GFX,我们来看看Adafruit_GFX的声明
class Adafruit_GFX : public Print
通过上面三个例子,我们发现他们对应的类有两个继承自Stream类,一个继承自Print类,我们再来看看这两个类:
class Stream : public Print
{
protected:
unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read
unsigned long _startMillis; // used for timeout measurement
int timedRead(); // read stream with timeout
int timedPeek(); // peek stream with timeout
int peekNextDigit(LookaheadMode lookahead, bool detectDecimal); // returns the next numeric digit in the stream or -1 if timeout
public:
virtual int available() = 0;
virtual int read() = 0;
virtual int peek() = 0;
Stream() {_timeout=1000;}
// parsing methods
void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
unsigned long getTimeout(void) { return _timeout; }
bool find(char *target); // reads data from the stream until the target string is found
bool find(uint8_t *target) { return find ((char *)target); }
// returns true if target string is found, false if timed out (see setTimeout)
bool find(char *target, size_t length); // reads data from the stream until the target string of given length is found
bool find(uint8_t *target, size_t length) { return find ((char *)target, length); }
// returns true if target string is found, false if timed out
bool find(char target) { return find (&target, 1); }
bool findUntil(char *target, char *terminator); // as find but search ends if the terminator string is found
bool findUntil(uint8_t *target, char *terminator) { return findUntil((char *)target, terminator); }
bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen); // as above but search ends if the terminate string is found
bool findUntil(uint8_t *target, size_t targetLen, char *terminate, size_t termLen) {return findUntil((char *)target, targetLen, terminate, termLen); }
long parseInt(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR);
// returns the first valid (long) integer value from the current position.
// lookahead determines how parseInt looks ahead in the stream.
// See LookaheadMode enumeration at the top of the file.
// Lookahead is terminated by the first character that is not a valid part of an integer.
// Once parsing commences, 'ignore' will be skipped in the stream.
float parseFloat(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR);
// float version of parseInt
size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer
size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); }
// terminates if length characters have been read or timeout (see setTimeout)
// returns the number of characters placed in the buffer (0 means no valid data found)
size_t readBytesUntil( char terminator, char *buffer, size_t length); // as readBytes with terminator character
size_t readBytesUntil( char terminator, uint8_t *buffer, size_t length) { return readBytesUntil(terminator, (char *)buffer, length); }
// terminates if length characters have been read, timeout, or if the terminator character detected
// returns the number of characters placed in the buffer (0 means no valid data found)
// Arduino String functions to be added here
String readString();
String readStringUntil(char terminator);
protected:
long parseInt(char ignore) { return parseInt(SKIP_ALL, ignore); }
float parseFloat(char ignore) { return parseFloat(SKIP_ALL, ignore); }
// These overload exists for compatibility with any class that has derived
// Stream and used parseFloat/Int with a custom ignore character. To keep
// the public API simple, these overload remains protected.
struct MultiTarget {
const char *str; // string you're searching for
size_t len; // length of string you're searching for
size_t index; // index used by the search routine.
};
// This allows you to search for an arbitrary number of strings.
// Returns index of the target that is found first or -1 if timeout occurs.
int findMulti(struct MultiTarget *targets, int tCount);
};
class Print
{
private:
int write_error;
size_t printNumber(unsigned long, uint8_t);
size_t printFloat(double, uint8_t);
protected:
void setWriteError(int err = 1) { write_error = err; }
public:
Print() : write_error(0) {}
int getWriteError() { return write_error; }
void clearWriteError() { setWriteError(0); }
virtual size_t write(uint8_t) = 0;
size_t write(const char *str) {
if (str == NULL) return 0;
return write((const uint8_t *)str, strlen(str));
}
virtual size_t write(const uint8_t *buffer, size_t size);
size_t write(const char *buffer, size_t size) {
return write((const uint8_t *)buffer, size);
}
// default to zero, meaning "a single write may block"
// should be overriden by subclasses with buffering
virtual int availableForWrite() { return 0; }
size_t print(const __FlashStringHelper *);
size_t print(const String &);
size_t print(const char[]);
size_t print(char);
size_t print(unsigned char, int = DEC);
size_t print(int, int = DEC);
size_t print(unsigned int, int = DEC);
size_t print(long, int = DEC);
size_t print(unsigned long, int = DEC);
size_t print(double, int = 2);
size_t print(const Printable&);
size_t println(const __FlashStringHelper *);
size_t println(const String &s);
size_t println(const char[]);
size_t println(char);
size_t println(unsigned char, int = DEC);
size_t println(int, int = DEC);
size_t println(unsigned int, int = DEC);
size_t println(long, int = DEC);
size_t println(unsigned long, int = DEC);
size_t println(double, int = 2);
size_t println(const Printable&);
size_t println(void);
virtual void flush() { /* Empty implementation for backward compatibility */ }
};
我们发现Stream类继承自Print类,而我们熟悉的println、print、write等输出函数就在Print中,available()、read()、peak()等输入函数在Stream中。而write、available()、read()、peek()等是纯虚函数,Print类中的和输出有关的函数最后调用的都是write函数,Stream类中和读取有关的函数最后都是调用的read()和peak()。
子类通过实现以上的纯虚函数来实现输入输出函数的重定向。子类所示例化的对象都可以使用这些函数来进行输入和输出。
在使用c语言开发时,我们曾通过重写fputc()函数,来重定向的printf函数。重定向到串口1时就只能输出到串口1,而不能输出到其他的输出设备中。而使用c++类的纯虚函数重定向后,每个实例化的输出设备都有自己的输出函数。并且相比于printf,arduino的println和print通过函数重载提供了更为方便的接口。
由此我们可以对Arduino输入输出流的继承关系用下图来表示:
二、设计自己的输入输出类
我在之前的文章中说过,我并不是为了全盘移植Arduino的东西。对于Arduino输入输出类暂时无法摸清底层硬件的具体实现,为了自己的底层库兼容,我以Arduino的Stream类和Print类作为参考,自己实现了outputStream和inputStream类,其中既移植了部分Arduino输入输出类中的函数,也增加了自己的思想和风格。
首先是输入输出流的继承关系,我将输入和输出分开,作为两个独立的基类,而不像Arduino把输入类继承自输出类,以此我自己的输入输出类的继承关系如图所示:
下面我将对这两个类进行说明。
2.1 outputStream
outputStream中有两个纯虚函数成员:
virtual size_t write(uint8_t) = 0;
virtual size_t write(const uint8_t *, size_t) = 0;
这两个纯虚函数分别用于输出一个字节和输出二进制数据。类中的其他的输出函数如print、println等最终调用的都是这两个函数,因此子类只需要将这两个纯虚函数实现,就可以实例化一个输出设备。
在output类中还有两个比较重要的私有成员函数:
size_t printNumber(unsigned long, uint8_t);
size_t printFloat(double, uint8_t);
这printNumber()可以将整数以任意进制输出,最高可以使用到16进制。print和println函数通过参数缺省的特性,将默认值设为10进制。printFloat()可以将浮点数以保留任意位小数输出,print和println函数通过参数缺省的特性,设置默认值为保留小数点后2位。print和println输出整数和浮点数都会调用这两个函数。
再来看看outputStream完整声明:
class outputStream
{
private:
size_t printNumber(unsigned long, uint8_t);
size_t printFloat(double, uint8_t);
public:
virtual size_t write(uint8_t) = 0;
size_t write(const char *str)
{
if (str == NULL)
return 0;
return write((const uint8_t *)str, strlen(str));
}
virtual size_t write(const uint8_t *, size_t) = 0;
size_t write(const char *buffer, size_t size)
{
return write((const uint8_t *)buffer, size);
}
// size_t print(const __FlashStringHelper *);
size_t print(const String &);
size_t print(const char[]);
size_t print(char);
size_t print(unsigned char, int = DEC);
size_t print(int, int = DEC);
size_t print(unsigned int, int = DEC);
size_t print(long long, int = DEC);
size_t print(unsigned long long, int = DEC);
size_t print(double, int = 2);
// size_t print(const Printable &);
// size_t println(const __FlashStringHelper *);
size_t println(const String &s);
size_t println(const char[]);
size_t println(char);
size_t println(unsigned char, int = DEC);
size_t println(int, int = DEC);
size_t println(unsigned int, int = DEC);
size_t println(long long, int = DEC);
size_t println(unsigned long long, int = DEC);
size_t println(double, int = 2);
// size_t println(const Printable &);
size_t println(void) { return print("\r\n"); };
template <typename T>
outputStream &operator<<(T out)
{
print(out);
return *this;
}
outputStream &operator<<(String &str)
{
print(str);
return *this;
}
};
首先对比Arduino的输出类Print,Arduino中的write、print、println以及printNumber、printFloat等基本上移植了过来。Print中的flush、availableForWrite以及和error相关的函数在使用时基本上不会用到,所有没有移植。
在我自己的outputStream中添加了如下的成员函数:
template <typename T>
outputStream &operator<<(T out)
{
print(out);
return *this;
}
outputStream &operator<<(String &str)
{
print(str);
return *this;
}
通过重载输出运算符<<,使得outputStream类支持了类似c++中std::cout的功能。这是我对Print的一个扩展。
接下来,通过串口输出来展示其功能(硬件串口类HardwareUART继承自outputStream和inputStream,以后会进行介绍)
#include "User.h"
HardwareUART UART(UART_1);
int main()
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
systick_init();
adc_init();
/********************************************************************/
UART.begin(115200);
int a = 100, pi = PI;
String str = "hello wold string";
UART.print("a=");
UART.print(a);
UART.print(" 0x");
UART.println(a, HEX);
UART.print("pi=");
UART.print(pi);
UART.print(" ");
UART.println(pi, 6);
UART.print("hello wrold\r\n");
UART.println("hello wrold");
UART.println(str);
UART << "print by \"<<\":" << endl;
UART << "a=" << a << endl;
UART << "pi=" << pi << endl;
UART << "Hello wrold" << endl;
UART << str << endl;
UART.println(123);
UART.println(123.45);
UART << 123 << " " << 123.45 << endl;
/********************************************************************/
while (1)
{
}
}
通过以上示例,大家应该不难发现,使用<<输出运算符会比print和println易用性更强一些。
2.2 inputStream
对于inputStream的设计会比Ardunio的Stream简洁许多,保留了Stream中的available()、read()、peek()。重载了>>输入运算符,使得inputStream子类实例化的输入设备支持c++中类似于std::cin的功能。inputSream大部分的输入函数都是设计为位阻滞函数,没有像Arduino那样可以设置等待时间,在这一点上我嘚inputStream还不够完善,后面还会继续进行修改和扩展。同时inputStream中带有一个缓冲区指针,指向输入设备的接收缓冲区(例如之前的文章中提到的串口接收缓冲区)。
首先介绍成员结构体指针:__rec_buf *buf;
__rec_buf 在之前的文章:从新建工程开始使用C++开发单片机(以STM32为例):五、C语言接口层之串口UART 进行了介绍,这里再具体展现一下:
typedef struct
{
volatile uint8_t buf[256]; //接收缓冲区
volatile uint8_t write_index; //写指针
volatile uint8_t read_index; //读指针
volatile uint16_t data_size; //缓冲区接收到的数据长度
/* data */
}__rec_buf;
inputStream中的read、peek、available就是在读取和维护这个缓存区。在串口的类中,将__rec_buf指针指向所对应的串口缓冲区,就可以实现对串口输入的读取。对于例如键盘的类,也可以通过建立上面的缓冲区,将指针指向其缓冲区,实现对键盘输入的读取。
相比于Arduino的Stream强调查找,例如和find相关的函数,inputStream更加强调多样化的扫描输入,因此我并没有移植Stream中find相关的函数。对于find我更偏向于把它放在String字符串类中。inputStream类有许多的scan函数,和outputStream中的print相对应,用于实现类似于C语言中scanf的功能。并且设计了scanNumber()和scanFloat()对应outputSream中的printNumber()和printFloat(),大部分的scan数字的函数底层都是scanNumber()和scanFloat()。
再来看看outputStream完整声明:
class inputStream
{
protected:
__rec_buf *buf;
public:
virtual int available();
virtual int read();
virtual int peek();
/***阻滞读取**********************/
long scanNumber();
double scanFloat();
int getc();
int scan(char *); //扫描字符串
int scan(String &);
int scan(char &);
int scan(unsigned char &); //扫描字符
int scan(int &); //扫描数字
int scan(unsigned int &); //扫描数字
int scan(long long &); //扫描数字
int scan(unsigned long long &); //扫描数字
int scan(double &); //扫描浮点数
int scan(float &); //扫描浮点数
template <typename T>
inputStream &operator>>(T &out)
{
scan(out);
return *this;
}
};
相比于Arduino的Stream是不是简单了很多?
在scan的基础上,重载了>>输入运算符,和outputStream中的<<输出运算符相对应,增加了易用性。
template <typename T>
inputStream &operator>>(T &out)
{
scan(out);
return *this;
}
接下来这段代码用来展示其功能:
#include "User.h"
HardwareUART UART(UART_1);
int main()
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
systick_init();
adc_init();
/********************************************************************/
UART.begin(115200);
int a;
float f;
String str;
char buf[100];
UART << "scan example:" << endl;
UART.scan(a);
UART.scan(f);
UART.scan(str);
UART.scan(buf);
UART << "a=" << a << " f=" << f << " String is:" << str << " buf is" << buf << endl;
UART << ">> example:" << endl;
UART >> a >> f >> str >> buf;
UART << "a=" << a << " f=" << f << " String is:" << str << " buf is" << buf;
/********************************************************************/
while (1)
{
}
}
串口输入为:
11 11.35 str buf
22,3.14 hello,world hello
串口输出:
三、总结
这两个类是我花费大量时间所设计出来的。在目前我已完成的内容中,硬件串口、屏幕输出、AT24C04等外设和外部硬件设备的驱动类都继承了这两个类,实践证明所花的时间也是值得的。相比于C语言的sprintf、printf以及直接调用C语言层的接口,使用类来封装会占用不少的单片机资源从而影响到执行的效率,不过对于现在的内存高达几百k甚至几M的单片机来说,这些效率和内存的牺牲换来的更高效率的开发是远远值得的。在上面的例子中,有使用到了String类,这是我从Arduino移植过来的WString,非常的好用,后面的文章将会介绍到。
附:完整代码
/*file : inputStream.h*/
#ifndef __OUTPUT_STREAM_H
#define __OUTPUT_STREAM_H
#include <stdio.h>
#include "WString.h"
#include "headfile.h"
#define DEC 10
#define HEX 16
#define OCT 8
#ifdef BIN // Prevent warnings if BIN is previously defined in "iotnx4.h" or similar
#undef BIN
#endif
#define BIN 2
//using std::endl;
#define endl "\r\n"
class outputStream
{
private:
size_t printNumber(unsigned long, uint8_t);
size_t printFloat(double, uint8_t);
public:
virtual size_t write(uint8_t) = 0;
size_t write(const char *str)
{
if (str == NULL)
return 0;
return write((const uint8_t *)str, strlen(str));
}
virtual size_t write(const uint8_t *, size_t) = 0;
size_t write(const char *buffer, size_t size)
{
return write((const uint8_t *)buffer, size);
}
// size_t print(const __FlashStringHelper *);
size_t print(const String &);
size_t print(const char[]);
size_t print(char);
size_t print(unsigned char, int = DEC);
size_t print(int, int = DEC);
size_t print(unsigned int, int = DEC);
size_t print(long long, int = DEC);
size_t print(unsigned long long, int = DEC);
size_t print(double, int = 2);
// size_t print(const Printable &);
// size_t println(const __FlashStringHelper *);
size_t println(const String &s);
size_t println(const char[]);
size_t println(char);
size_t println(unsigned char, int = DEC);
size_t println(int, int = DEC);
size_t println(unsigned int, int = DEC);
size_t println(long long, int = DEC);
size_t println(unsigned long long, int = DEC);
size_t println(double, int = 2);
// size_t println(const Printable &);
size_t println(void) { return print("\r\n"); };
template <typename T>
outputStream &operator<<(T out)
{
print(out);
return *this;
}
outputStream &operator<<(String &str)
{
print(str);
return *this;
}
};
#endif
/*file : outputStream.cpp*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdarg.h>
#include "outputStream.h"
// Public Methods //
/* default implementation: may be overridden */
size_t outputStream::print(const String &s)
{
return write(s.c_str(), s.length());
}
size_t outputStream::print(const char str[])
{
return write(str);
}
size_t outputStream::print(char c)
{
return write(c);
}
size_t outputStream::print(unsigned char b, int base)
{
return print((unsigned long long)b, base);
}
size_t outputStream::print(int n, int base)
{
return print((long long)n, base);
}
size_t outputStream::print(unsigned int n, int base)
{
return print((unsigned long long)n, base);
}
size_t outputStream::print(long long n, int base)
{
if (base == 0)
{
return write(n);
}
else if (base == 10)
{
if (n < 0)
{
int t = print('-');
n = -n;
return printNumber(n, 10) + t;
}
return printNumber(n, 10);
}
else
{
return printNumber(n, base);
}
}
size_t outputStream::print(unsigned long long n, int base)
{
if (base == 0)
return write(n);
else
return printNumber(n, base);
}
size_t outputStream::print(double n, int digits)
{
return printFloat(n, digits);
}
size_t outputStream::println(const String &s)
{
size_t n = print(s);
n += println();
return n;
}
size_t outputStream::println(const char c[])
{
size_t n = print(c);
n += println();
return n;
}
size_t outputStream::println(char c)
{
size_t n = print(c);
n += println();
return n;
}
size_t outputStream::println(unsigned char b, int base)
{
size_t n = print(b, base);
n += println();
return n;
}
size_t outputStream::println(int num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t outputStream::println(unsigned int num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t outputStream::println(long long num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t outputStream::println(unsigned long long num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t outputStream::println(double num, int digits)
{
size_t n = print(num, digits);
n += println();
return n;
}
// Private Methods /
size_t outputStream::printNumber(unsigned long n, uint8_t base)
{
char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
char *str = &buf[sizeof(buf) - 1];
*str = '\0';
// prevent crash if called with base == 1
if (base < 2)
base = 10;
do
{
char c = n % base;
n /= base;
*--str = c < 10 ? c + '0' : c + 'A' - 10;
} while (n);
return write(str);
}
size_t outputStream::printFloat(double number, uint8_t digits)
{
size_t n = 0;
if (isnan(number))
return print("nan");
if (isinf(number))
return print("inf");
if (number > 4294967040.0)
return print("ovf"); // constant determined empirically
if (number < -4294967040.0)
return print("ovf"); // constant determined empirically
// Handle negative numbers
if (number < 0.0)
{
n += print('-');
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
for (uint8_t i = 0; i < digits; ++i)
rounding /= 10.0;
number += rounding;
// Extract the integer part of the number and print it
unsigned long long int_part = (unsigned long long)number;
double remainder = number - (double)int_part;
n += print(int_part);
// Print the decimal point, but only if there are digits beyond
if (digits > 0)
{
n += print('.');
}
// Extract digits from the remainder one at a time
while (digits-- > 0)
{
remainder *= 10.0;
unsigned int toPrint = (unsigned int)(remainder);
n += print(toPrint);
remainder -= toPrint;
}
return n;
}
/*file : inputStream.h*/
#ifndef __INPUT_STREAM_H
#define __INPUT_STREAM_H
#include "WString.h"
#include "headfile.h"
class inputStream
{
protected:
__rec_buf *buf;
public:
virtual int available();
virtual int read();
virtual int peek();
/***阻滞读取**********************/
long scanNumber();
double scanFloat();
int getc();
int scan(char *); //扫描字符串
int scan(String &);
int scan(char &);
int scan(unsigned char &); //扫描字符
int scan(int &); //扫描数字
int scan(unsigned int &); //扫描数字
int scan(long long &); //扫描数字
int scan(unsigned long long &); //扫描数字
int scan(double &); //扫描浮点数
int scan(float &); //扫描浮点数
template <typename T>
inputStream &operator>>(T &out)
{
scan(out);
return *this;
}
};
#endif
/*file : inputStream.cpp*/
#include "inputStream.h"
#include "math.h"
int inputStream::available()
{
return buf->data_size;
}
int inputStream::read()
{
if (buf->data_size == 0)
{
return -1;
}
buf->data_size--;
return buf->buf[buf->read_index++];
}
int inputStream::peek()
{
if (buf->data_size == 0)
{
return -1;
}
return buf->buf[buf->read_index];
}
int inputStream::getc()
{
while (!available())
;
return read();
}
long inputStream::scanNumber()
{
char ch;
do
{
ch = getc();
} while (ch != '-' && (ch <= '0' || ch >= '9'));
long res;
int fu_flag = 0;
if (ch == '-')
{
res = 0;
fu_flag = 1;
}
else
{
res = ch - '0';
}
ch = getc();
while (ch >= '0' && ch <= '9')
{
res *= 10;
res += (ch - '0');
ch = getc();
}
if (fu_flag)
res = -res;
return res;
}
double inputStream::scanFloat()
{
char ch;
do
{
ch = getc();
} while (ch != '-' && (ch <= '0' || ch >= '9'));
double res;
int fu_flag = 0;
if (ch == '-')
{
res = 0;
fu_flag = 1;
}
else
{
res = (double)(ch - '0');
}
ch = getc();
while (ch >= '0' && ch <= '9')
{
res *= 10.0;
res += (double)(ch - '0');
ch = getc();
}
if (ch != '.')
{
if (fu_flag)
res = -res;
return res;
}
double d = 0.1;
while (1)
{
ch = getc();
if (ch < '0' || ch > '9')
break;
res += d * (double)(ch - '0');
d /= 10.0;
}
if (fu_flag)
res = -res;
return res;
}
int inputStream::scan(char &in)
{
in = getc();
return in;
}
int inputStream::scan(unsigned char &in)
{
in = scanNumber();
return in;
}
int inputStream::scan(int &in)
{
in = scanNumber();
return in;
}
int inputStream::scan(unsigned int &in)
{
in = scanNumber();
return in;
}
int inputStream::scan(long long &in)
{
in = scanNumber();
return in;
}
int inputStream::scan(unsigned long long &in)
{
in = scanNumber();
return in;
}
int inputStream::scan(double &in)
{
in = scanFloat();
return (int)in;
}
int inputStream::scan(float &in)
{
in = scanFloat();
return (int)in;
}
int inputStream::scan(char *in)
{
char ch;
do
{
ch = getc();
} while (ch <= ' ' || ch > '~');
int pos = 0;
in[pos++] = ch;
while (1)
{
ch = getc();
if (ch <= ' ' || ch > '~')
{
break;
}
in[pos++] = ch;
}
in[pos] = '\0';
return pos;
}
int inputStream::scan(String &in)
{
in = "";
char ch;
do
{
ch = getc();
} while (ch <= ' ' || ch > '~');
in += ch;
while (1)
{
ch = getc();
if (ch <= ' ' || ch > '~')
{
break;
}
in += ch;
}
return in.length();
}