views:

66

answers:

2

On my 8-bit Freescale HCS08 micro, whenever I call a library function that returns values to pointers I pass it, and I don't really want them, I threw in a NULL, e.g.

UART_SendBlock((char *)txstr, strlen(txstr), NULL);

The type of the last argument is uint16_t * and returns the number of characters actually sent, a value I don't care about.

However, I was having problems with port A on my micro being hosed every time that function was called, and debugging pointed me to that argument screwing things up. Port A's configuration registers live at addresses 0x0000 and 0x0001, which is where NULL (aka (void *)0) points. I thought NULL was somehow magic where it wouldn't actually do anything, but it doesn't seem so.

My workaround feels really hack:

#define MNUL (void *)(&mynull)
uint32_t mynull;

Is there a better solution? I tried defining MNUL to an unused segment of memory on my processor, but that causes an immediate reset.

+3  A: 

The function is trying to write a value into wherever the last argument points. You're passing in NULL (0x0000), so the result is being written to the memory location 0x0000, or your port A. Usually (in general programming) the function would check the argument and not try to write to the location if it was NULL, but it appears this function doesn't follow that convention. You need to allocate a variable for the function to write its result to, even if you aren't going to use it.

Ian Wetherbee
In deeply embedded systems (an 8-bit micro certainly qualifies) you won't have very many sanity checks on arguments, if any at all. I would not expect any protection from the NULL pointer, especially not when it is a perfectly legal address of a hardware device in the platform.
RBerteig
Even in non-embedded systems, if the function isn't documented to handle NULL pointers, then the assumption is that you cannot pass a NULL pointer to it. This is one of the 'Ground Rules of Programming': http://blogs.msdn.com/b/oldnewthing/archive/2006/03/20/555511.aspx
Michael Burr
+7  A: 

Unless the documentation for UART_SendBlock states that passing it a NULL pointer is ok , you probably get undefined behavior if you do - and in this case it seems the function just writes to the address you pass it, address 0 - which would go under "undefined behavior".

Just call it with a parameter, there's no reason to be "clever" about it.

uint16_t unused_16;
UART_SendBlock((char *)txstr, strlen(txstr), &unused_16);

If you are resource constrained, make unused_16 a global and reuse it in other places

nos
I am a bit constrained; my little snippet lives in some general purpose include file, so I figured I could allocate a `uint32` and have that catch everything. Am I pointing the gun at my foot when I typecast it to a void pointer? If I used it for some string function it would happily drift off into oblivion I suppose...
Nick T
You will get in trouble passing your MNUL to a function that doesn't really expect "NULL" pointer, but rather something larger than a uint32_t, so be careful - thus the suggestion of rather making a global and naming it unused_xx to make it more explicit. Casting it to a void* will probably also make it swallow warnings about wrong use of it. But if you're really resource constrained also for the stack space, it might be a justifiable hack
nos
Also, if the author of UART_SendBlock didn't see fit to provide a way to ignore the number of chars actually sent, that's probably because the author of UART_SendBlock thinks you need to know. For example, perhaps the function might send only part of the data, or none, for no good reason (or at least, no predictable reason). If you don't care whether the data gets sent or not, you can resolve this NULL issue and save valuable code space by not bothering to call UART_SendBlock at all ;-)
Steve Jessop