I want to write a macro to write a string, using the compile-time optimisation of knowing the length of a string literal. But I need to detect misuse, using pointers.
Here's what I mean:
void transmit(const char *data, int length);
#define tx_string(x) transmit((x), sizeof(x) -1)
void func(char *badmsg) {
tx_string("GO"); // ok
tx_string(badmsg); // not OK
}
With the second call, the size will be nonsense (sizeof a pointer).
I want to produce a compile-time error if I attempt to use tx_string on anything other than a string literal. This is using gcc; is there some gcc thing I can use to do this?
Edit: I work with data buffers that may contain nulls or not be terminated by nulls. I REALLY want to prevent pointers being used for this, and prevent run-time strlen()
use.
Edit 2:
Here's an example which would cause a problem. I'll invent an imaginary protocol where I have to tell a 16-bit microcontroller an address using the command GO followed by an address as 16-bit raw (two 8-bit characters), and I want to go from address 0.
#define GOSEQ "GO\000\000"
void func(void) {
char *bad = GOSEQ;
tx_string(GOSEQ); // ok, sends 4 bytes: GO and two zero bytes
tx_string(bad); // bad, using runtime strlen sends two characters "GO"
}
I feel sure there must be some kind of gcc builtin check for this. I see the Linux kernel sources using compile-time distinction tricks like this a lot.. but can't lay my hands on a specific one quickly.
So far "Windows programmer"'s idea looks good, but a more meaningful compile-time error would be a bonus.
In general, since you cannot use string concatenation with pointers etc, maybe you can use:
#define STRLIT(x) x ""
If the argument to STRLIT
is not a string literal, you will get a compilation error.
Adapting the general to your specific macro:
#define tx_string(x) transmit((x ""), sizeof(x) - 1)
You can do this:
#define tx_string(x) transmit(x, strlen(x)) // No need for extra parentheses
GCC will optimize out the strlen
call, and I'm sure other compilers will too. Don't waste your time on this stuff.
Test file:
#include <string.h>
void transmit(const char *, size_t);
#define tx_string(x) transmit(x, strlen(x))
void func(void)
{
tx_string("abcdef");
}
Resulting assembly:
I trimmed noise out of the assembly, this is the important stuff. Notice that it never calls strlen
, instead it just uses the number 6:
.LC0:
.string "abcdef"
func:
movl $6, %esi
movl $.LC0, %edi
jmp transmit
#define tx_string(x) ("i came, i concatenated, i discarded " x, transmit((x), sizeof(x) - 1))
Not quite perfect because some joker could call tx_string(+1)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With