I am trying to write a very simple program to output a serial string including hex codes when I press a button. It works fine if the string does not include 0x00, but if it does this is treated as 'end of string' and does not output.
printf ("\x01\x02\x00\x03\x04")
SBUF =0x01 SBUF =0x02 SBUF =0x00 SBUF =0x03 SBUF =0x04
Or use fwrite() to write a whole section of memory. It's not meant for strings, but that's fine, because what you have there is no string. Caveat: I haven't checked whether Keil's libc supports fwrite(), but I think it should.
"I haven't checked whether Keil's libc supports fwrite()" Nope - it doesn't. See Appendix A in the manual, which lists the differences from ANSI 'C' - including the library functions which are and are not included. "I think it should." Why on earth would it?? fwrite() assumes that you have a file system to write to (the clue is in the 'f') - that's most unlikely with an 8051 (even if you did, it'd have to be pretty proprietary, so you'd have to write your own fwrite anyway!)
Why on earth would it?? Because an optimized library implementation of fwrite() could be better for the user than rolling his own putchar() loop in C. fwrite() assumes that you have a file system to write to (the clue is in the 'f') I don't agree here. fwrite() doesn't assume a whole filesystem. It only assumes a valid FILE * argument. It doesn't care how you came by it. If Keil don't want to implement fopen()/fclose() that's fine with me. But IMHO that's not a strict reason to forbid something like
fwrite(mybuffer, itslength, 5, stdout)
"optimized library implementation of fwrite() could be better for the user than rolling his own putchar() loop in C." But who said fwrite() would have to end up at a serial port? If Keil were to support fwrite() it would have to support writing to all sorts of devices - parallel ports, shared RAM, FIFOs, USB, CAN, etc, etc, etc,... It'd be impossible to optimise such a thing! "It only assumes a valid FILE * argument. It doesn't care how you came by it." But it would have to know the implementation details of the interface indicated by that FILE * argument in order to be able to write to it!
But who said fwrite() would have to end up at a serial port I didn't. But that shouldn't matter. It's similar to memcpy() in goal: both can easily be implemented by the user as a loop in C. fwrite() is defined to have the same effect as a loop of putc() (or putchar(), if you like) calls. memcpy() is defined to behave the same as a simple copy loop in C. So why are these "obvious" things defined as ANSI C Standard Library functions? Because a compiler implementor can do things that the user can't do, or which are rather difficult to achieve for a user. E.g. setup costs for a long string of calls to putc() can be avoided if you know you'll be doing lots of putc()s in a row. Calling a particular incarnation of putchar() in a tight loop may or not be wasteful because of such setup costs. If it is, having a hand-optimized fwrite() becomes a very useful thing. For now, stdout and stderr would be the only valid FILE* arguments to fwrite(), and a companion stdin for fread(), of course. But once these are in place, this concept could indeed be extended to support other types of output.
But what is stdout? How does one send a byte to it?? - see above! Stdout is where printf() sends its output. Keil have implemented printf() and allowed us to change the device treated as being stdout by modifying the putchar() function.