我想编写一个宏来编写一个字符串,使用知道字符串文字长度的编译时优化。但我需要使用指针来检测误用。
这就是我的意思:
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
}
使用第二个调用时,大小将是无意义的(指针的大小)。
如果我尝试在除字符串文字之外的任何内容上使用tx_string,我想产生编译时错误。这是使用gcc;我可以使用一些gcc来做这件事吗?
编辑:我处理可能包含空值或不以空值终止的数据缓冲区。我真的想阻止使用指针,并阻止运行时strlen()
使用。
编辑2:
这是一个会导致问题的例子。 我将发明一个假想的协议,我必须使用命令GO后跟地址为16位原始(两个8位字符)告诉16位微控制器一个地址,我想从地址0开始。 / p>
#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"
}
我确信必须有某种gcc内置检查。我看到Linux内核源代码使用这样的编译时区分技巧很多..但是不能快速地把手放在特定的一个上。
到目前为止,“Windows程序员”的想法看起来不错,但更有意义的编译时错误将是一个奖励。
答案 0 :(得分:9)
一般情况下,由于你不能使用字符串连接和指针等,也许你可以使用:
#define STRLIT(x) x ""
如果STRLIT
的参数不是字符串文字,则会出现编译错误。
使通用适应您的特定宏:
#define tx_string(x) transmit((x ""), sizeof(x) - 1)
答案 1 :(得分:4)
你可以这样做:
#define tx_string(x) transmit(x, strlen(x)) // No need for extra parentheses
GCC将优化strlen
电话,我相信其他编译器也会。不要在这些东西上浪费你的时间。
测试文件:
#include <string.h>
void transmit(const char *, size_t);
#define tx_string(x) transmit(x, strlen(x))
void func(void)
{
tx_string("abcdef");
}
结果汇编:
我将噪音从装配中消除,这是重要的事情。请注意,它永远不会调用strlen
,而只是使用数字6:
.LC0:
.string "abcdef"
func:
movl $6, %esi
movl $.LC0, %edi
jmp transmit
答案 2 :(得分:1)
#define tx_string(x) ("i came, i concatenated, i discarded " x, transmit((x), sizeof(x) - 1))
不完美,因为一些小丑可以调用tx_string(+1)