如何在C宏中区分常量字符串和char *

时间:2011-11-10 05:08:12

标签: c macros c-preprocessor

我想编写一个宏来编写一个字符串,使用知道字符串文字长度的编译时优化。但我需要使用指针来检测误用。

这就是我的意思:

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程序员”的想法看起来不错,但更有意义的编译时错误将是一个奖励。

3 个答案:

答案 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)