How to distinguish a constant string from char * in a C macro

I want to write a macro to write a string using compile time optimization to find out the length of a string literal. But I need to detect misuse using pointers.

Here is 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 } 

On the second call, the size will be absurd (sizeof the pointer).

I want to create a compile-time error if I try to use tx_string for anything other than a string literal. This uses gcc; is there any gcc thing i can use for this?

Edit: I work with data buffers that may contain zeros or do not have to end with zeros. I REALLY want pointers not to be used for this, and prevent strlen() from being used at runtime.

Edit 2:

Here is an example that might cause the problem. I will come up with an imaginary protocol where I have to tell the 16-bit microcontroller the address using the GO command, followed by the address in the form of 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 am sure there must be some kind of gcc inline check for this. I can see Linux kernel sources using compile-time markup tricks like this, but can't quickly spread my hands.

While the idea of ​​a "Windows programmer" looks good, a bonus will be a more significant compilation error.

+6
source share
3 answers

In general, since you cannot use string concatenation with pointers, etc., perhaps you can use:

 #define STRLIT(x) x "" 

If the argument STRLIT 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) 
+9
source

You can do it:

 #define tx_string(x) transmit(x, strlen(x)) // No need for extra parentheses 

GCC optimizes the strlen call, and I am sure that other compilers will also be. Do not waste time on this.

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 removed the noise from the assembly, this is important material. Note that it never calls strlen , instead it just uses the number 6:

 .LC0: .string "abcdef" func: movl $6, %esi movl $.LC0, %edi jmp transmit 
+4
source
 #define tx_string(x) ("i came, i concatenated, i discarded " x, transmit((x), sizeof(x) - 1)) 

Not entirely perfect, because some joker could call tx_string (+1)

+1
source

Source: https://habr.com/ru/post/901177/


All Articles