【问题标题】:With the Arduino Ethernet shield, what's the difference between `write()`, `print()`, and `printIn()`?使用 Arduino 以太网扩展板,`write()`、`print()` 和 `printIn()` 之间有什么区别?
【发布时间】:2013-04-26 22:15:13
【问题描述】:

使用Arduino Ethernet Server Library有什么区别:

server.write(data);, server.print(data);,和 server.println(data);

我知道printIn 添加了一个新行,而print 没有。我找不到server.write(); 的任何示例。

【问题讨论】:

    标签: arduino ethernet


    【解决方案1】:

    (长答案,如果不方便,请跳至底部的 TL;DR

    print()write() 来自哪里

    要找出答案,我们可以查看源代码。 Server 是在arduino/libraries/Ethernet/EthernetServer.h 中定义的EthernetServer 类的一个实例(仅限选定的行)

    #include "Server.h"
    
    class EthernetClient;
    
    class EthernetServer : 
    public Server {
    private:
    public:
      virtual size_t write(uint8_t);
      virtual size_t write(const uint8_t *buf, size_t size);
      using Print::write;
    };
    

    好的,所以它是ServerServer 定义在 /usr/share/arduino/hardware/arduino/cores/arduino/Server.h 中,而且内容很少:

    class Server : public Print {
    public:
      virtual void begin() =0;
    };
    

    这意味着 server 是Print 的子类,因此我们可以在那里查找write()print() 之间的差异。

    print()write() 参数

    我们看到这个类(即Print)定义了许多重载的print()方法:

    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&);
    

    和三个重载的write() 方法:

    virtual size_t write(uint8_t) = 0;
    size_t write(const char *str) { return write((const uint8_t *)str, strlen(str)); }
    virtual size_t write(const uint8_t *buffer, size_t size);
    

    如你所见C字符串write使用块write(第三种方法),而在默认实现中,块写入使用字节写入(第一种方法),这是纯虚方法:virtual size_t write(uint8_t) = 0;。它必须在派生自Print 的每个类中被覆盖。此外,write() 块也可以被覆盖,以便更有效地写入多字节数据。

    所以,参数方面:

    • write():关于字节 (uint8_t)、字节缓冲区和字符数组指针(= 常规 C 字符串)
    • print():Arduino Strings、ints 和 longs(在任何基础上)、floats,以及从 Printable 派生的任何类,除了 chars 和 C 字符串。

    如您所见,在形式上,参数write()print() 之间几乎没有重叠。例如,只有write() 采用uint8_t,但只有print() 可以采用char。唯一重叠的区域是 C 风格的字符串:有 print(const char[]);write(const char *str);。然而,即使在像char 这样的情况下,print() 函数也会简单地调用write(uint8_t)

    size_t Print::print(char c)
    {
      return write(c);
    }
    

    print(char[]) 也是如此

    write() 在 `EthernetServer

    EthernetServer 类引入了块写入方法

    size_t EthernetServer::write(const uint8_t *buffer, size_t size) 
    

    EthernetServer 中,write(uint8_t) 只是简单地向块写入:

    size_t EthernetServer::write(uint8_t b) 
    {
      return write(&b, 1);
    }
    

    由于所有print() 调用和非uint8_t write() 调用都使用write(uint8_t)write(uint8_t*, size_t),因此在EthernetServer 类中,每个print/write 调用都是使用块进行的写。

    性能和在print()write() 之间进行选择

    thunking print() 函数(例如 print(char c))很可能会被 gcc 编译器内联,但如果您担心这一点,您可以调用 write() 而不是 print()

    可能想要调用write() 而不是print() 以节省几个时钟周期的一种情况是您持有byte/uint8_t 并且您需要打印那个。使用print(),您的数据需要转换为 4 字节值 (int),然后使用更多代码打印。在这种情况下,write() 会快一点。

    另一方面,代码一致性可能也很有价值。从这个角度来看,进行所有print() 调用可能是有意义的。

    然而,大多数时候,您的类型将决定调用 print() 函数:write 只能接受三种类型的输入。


    TL;DR:那么您的问题的答案是print()write() 之间没有太大区别,除了:

    • write() 方法(字节或块)是在任何情况下执行在某处发送字符的实际工作的方法。
    • write() 可以接受字节(uint8_t)、字节缓冲区和字符数组指针(= 常规 C 字符串)作为参数,而 print() 接受 Arduino Strings、ints 和 longs(在无论基数)、floats,以及从Printable 派生的任何类,以及chars 和C 字符串。所以我们可能会说write() 的级别低于print(),因为它只接受低级别的类型。
    • 大多数情况下,您的输出类型将决定使用哪一种。为了使代码最快使用write() 打印byte/uint8_t 类型,但print 无处不在让你的代码看起来好一点恕我直言(主要是因为它不会提高print()write()问题)。

    【讨论】:

    • 那么为什么会有人使用write()?如果你已经在使用它支持的变量类型会更快吗?
    • 感谢您指出这一点:这是答案中的一个缺陷。我试图解决它,但这使答案变得更长:(如果这不能解决问题,请告诉我。
    猜你喜欢
    • 2013-11-14
    • 1970-01-01
    • 2010-12-19
    • 2016-04-02
    • 2012-03-24
    • 1970-01-01
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多