My favorites | Sign in
Project Home Downloads Wiki Issues
New issue   Search
for
  Advanced search   Search tips   Subscriptions
Issue 527: Stream-based Wire library doesn't accept zero
9 people starred this issue and may be notified of changes. Back to list
Status:  Fixed
Owner:  dmel...@gmail.com
Closed:  Dec 2011


Sign in to add a comment
 
Project Member Reported by tom.i...@gmail.com, Apr 22, 2011
Wire.write(0x00);

gives the following error:

 error: call of overloaded 'write(int)' is ambiguous
Wire.h:55: note: candidates are: virtual void TwoWire::write(uint8_t)
Wire.h:56: note:                 virtual void TwoWire::write(const char*)

I solved it with an ugly hack, like so:

byte zero = 0x00;
Wire.write(zero);

A better solution would be nice.
Apr 25, 2011
#1 FRap...@gmail.com
you can cast it to remove the ambiguity

Wire.write((uint8_t) 0x00);

No ?
May 7, 2011
#2 paul.sto...@gmail.com
How about just adding these lines in Print.h?

    inline void write(unsigned long n) {write((uint8_t)n);}
    inline void write(long n) {write((uint8_t)n);}
    inline void write(unsigned int n) {write((uint8_t)n);}
    inline void write(int n) {write((uint8_t)n);}

These give the compiler the help it needs to "know" int (and the other 3) should use the uint8_t function.

Sep 17, 2011
#3 andrewwi...@gmail.com
It looks like in 1.0, you have to replace "void" with "size_t". My code that includes Wire.h works when I include it within the two "virtual"s:

    virtual size_t write(uint8_t) = 0;
    inline size_t write(unsigned long n) {write((uint8_t)n);}
    inline size_t write(long n) {write((uint8_t)n);}
    inline size_t write(unsigned int n) {write((uint8_t)n);}
    inline size_t write(int n) {write((uint8_t)n);}
    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);
Nov 30, 2011
#4 fabio.va...@gmail.com
Adding the following lines to Class Print in Print.h fixed the issue:

    inline size_t write(unsigned long n) {write((uint8_t)n);}
    inline size_t write(long n) {write((uint8_t)n);}
    inline size_t write(unsigned int n) {write((uint8_t)n);}
    inline size_t write(int n) {write((uint8_t)n);}
Nov 30, 2011
#5 paul.sto...@gmail.com
When I tested this before, putting them Wire.h (and any other derived classes) produced more efficient code than putten them in Print.h (the base class).
Nov 30, 2011
#6 paul.sto...@gmail.com
Since write now returns a size_t, those includes should be:

    inline size_t write(unsigned long n) { return write((uint8_t)n); }
    inline size_t write(long n) { return write((uint8_t)n); }
    inline size_t write(unsigned int n) { return write((uint8_t)n); }
    inline size_t write(int n) { return write((uint8_t)n); }

I'll attach a patch, which just adds these 4 linse to Wire.h


wire_inttypes.diff
574 bytes   View   Download
Dec 1, 2011
#7 fabio.va...@gmail.com
Looking good here.
Dec 2, 2011
Project Member #8 dmel...@gmail.com
https://github.com/arduino/Arduino/commit/6a6ed3d10ad1470283d7771906ce81ad97fa06f0

Although if this comes up for lots of other classes that inherit from Print, maybe we should move these overloads there?
Status: Fixed
Labels: -Milestone-1.0 Milestone-1.0.1
Dec 7, 2011
Project Member #9 dmel...@gmail.com
 Issue 743  has been merged into this issue.
May 31, 2012
#10 labre...@gmail.com
This change introduces the possibility of hard-to-detect bugs: attempting to write 2+ byte values via a single-argument form of Wire.write(...). With this change, the compiler will accept such code without complaint, and yet the non-lowest bytes will be silently dropped. Debugging this could become a nightmare: imagine if at first, the 2-byte integer you're sending over the wire is between 0 and 255. You test this and [for some reason] it works well. Then, sometime later, the value goes negative or becomes larger than 255. It is likely that the only way to detect such a change is to put a logic analyzer on the TWI bus, which probably means that the user has already spent some time looking for software errors on his/her side.

I understand that most people will be acquainted to TWI's single-byte-at-a-time nature. There's also Wire.Write(uint8_t * data, size_t quantity). Perhaps the person most likely to get things wrong is someone new to TWI. He or she would see an overload that accepts an int, and decide to use it, assuming it exists because an int is a valid datatype. Or, he or she simply writes the code and since it compiles, surely at least the _datatype_ is correct? Arduino is supposed to be friendly to beginners, but this change does exactly the opposite! Note that searching for "call of overloaded 'write(int)' is ambiguous" quickly brings one to a solution to the Wire.write(0) error message.

I suggest this change be reverted and that we go back to using C's type system as best as we can. C does not give very many compile-time guarantees; let us use the ones we have!
May 31, 2012
Project Member #11 dmel...@gmail.com
I think it's important that Wire.write(0) works without casting, but I'd be open to another solution for that.
Jun 6, 2012
#12 labre...@gmail.com
I did some more exploration of the issue and found out that one would need the -Wconversion compiler flag in order to catch integer narrowing. It turns out that the Arduino folks, far from using something like -Wall, use -w, which suppresses all warnings. So, unless they are willing to take a very different avenue than they do now (such as have an option to specify warning reporting level), the issue I raised is lost in the "noise".
Sign in to add a comment

Powered by Google Project Hosting