如何在c中使用三行​​语句的c宏

how to use c macro with three lines of statement in c

我想了解如何在我的 code.Can 中有效地使用 C 宏

#include<stdio.h>
#include<string.h>

void write_strongswan_conf(char buffer[1000],int buffer_size)
{
   FILE *fp;
   char delimiter[]="\n";
   fp = fopen( "strongswan.txt" , "a" );
   strcat(buffer,"\n");
   fwrite(buffer, 1 ,buffer_size+1, fp );
   printf("Data Written:%s",buffer);
   fclose(fp);
}

int main ()
{
    char wr_buffer[1000];
    int  wr_buffer_size =1;

    strcpy(wr_buffer,"STRONG SWAN CONFIGURATION FILE");
    wr_buffer_size = strlen(wr_buffer);
    write_strongswan_conf(wr_buffer,wr_buffer_size);

    strcpy(wr_buffer,"THIS IS THE SECOND LINE");
    wr_buffer_size = strlen(wr_buffer);
    write_strongswan_conf(wr_buffer,wr_buffer_size);

   return(0);
}

这是一个将新字符串附加到文件末尾的小程序,我现在有大约 25 个字符串要添加到 file.As,我必须重复写下面提到的三行明白了done.If我的理解是正确的我们将能够通过为这三行实现一个宏来减少LOC。

有人可以指导我吗?

    strcpy(wr_buffer,"STRONG SWAN CONFIGURATION FILE");
    wr_buffer_size = strlen(wr_buffer);
    write_strongswan_conf(wr_buffer,wr_buffer_size);

非常简单:

#define FOO(buf, str) \
    strcpy(buf, str); \
    write_strongswan_conf(buf, strlen(buf));

请注意,缓冲区大小参数是多余的,因此此处不需要。

然后通过以下方式引用它:

int main ()
{
    char wr_buffer[1000];

    FOO(wr_buffer, "STRONG SWAN CONFIGURATION FILE");
    FOO(wr_buffer, "THIS IS THE SECOND LINE");

    return(0);
}

如果您确实确实需要在宏中使用局部参数,您可以使用宏定义一个块:

#define FOO(buf, str) \
    { \
        int bsize; \
        strcpy(buf, str); \
        bsize = strlen(buf); \
        write_strongswan_conf(buf, bsize); \
    }

编辑: 感谢@jweyrich 和@BillLynch 的评论,他们指出了 potential pitfalls with the above method,并且在一个宏:

#define FOO(buf, str) \
    do { \
        strcpy(out, str); \
        write_strongswan_conf(buf, strlen(str)); \
    } while (0)

块结构还有一个好处,那就是如果您想在 C 的复合语句中使用宏。如果您采用上面的第一个定义并执行此操作:

if ( some_check )
     FOO(wr_buffer, "STRONG SWAN CONFIGURATION FILE");

您不会得到预期的结果,因为 if 仅适用于三个语句中的第一个。当然,一个好的解决方案是始终阻止您的语句:

if ( some_check ) {
     FOO(wr_buffer, "STRONG SWAN CONFIGURATION FILE");
}

但您也可以在宏定义中使用模式 do { ... } while (0),如上面第二个示例所示,这样也可以避免该问题。

请注意,有时在宏定义中将参数括起来很重要。我在上面没有这样做,因为这不太可能是个问题,但假设您有一个这样的宏:

#define MUL(X, Y)   (X * Y)

这看起来很天真。让我们试试吧:

int a = 2;
int b = 3
int c;

c = MUL(a, b);

这会生成:

c = (a * b);

请注意,#defines 非常直白。包括括号。预处理器只是直接替换我定义的所有内容。如果我的表达比较复杂:

c = MUL(a + 2, b + 3);

然后我得到:

c = (a + 2 * b + 3);

等等...这将给我一个等同于 a + (2*b) + 3 的结果,这可能不是我想要的。所以我用括号更仔细地定义宏:

#define MUL(X, Y)  ((X) * (Y))

现在上面将扩展为:c = ((a + 2) * (b + 3));

顺便说一下,如果您在使用宏 and/or 其他 #define 时遇到任何奇怪的行为,运行 只需 [=28= 上的预处理器就可以派上用场] 文件,它将在不编译的情况下展开所有 #defines。起初输出可能有点笨拙,但它可以方便地识别复杂宏的问题。您可以准确地看到它生成的内容。

在 Unix/Linux 中,您只需 运行 cpp 命令:cpp myfile.c > myfile.pre 或任何您想调用该文件的名称。如果您使用的是 Visual Studio,可能会有生成预处理文件的选项。

郑重声明,如果是我,我可能会将其设为函数,而不是宏。它当然只节省了一小部分执行时间,制作这样的宏。

与编码的所有方面一样:仔细考虑您正在做的事情很重要。 :)

这是我的镜头:

#define DO_SOMETHING(buf, str) \
    do { \
        const char *in = str; \
        char *out = buf; \
        const size_t len = strlen(in); \
        strcpy(out, in); \
        write_strongswan_conf(out, len);
    } while (0)

为什么要这样写宏?

  1. do {} while(0) 不是绝对必要的,但这是在条件内正确扩展多语句操作的唯一方法。例如,if (condition) DO_SOMETHING(...)。请参阅有关此的 more elaborate answer

  2. 创建临时变量的原因是宏参数每次出现在宏体中时都会被求值。例如,用 PRINT_ME_TWICE(i++) 调用宏 PRINT_ME_TWICE(intval) printf("%d\n", intval); printf("%d\n", intval); 将打印不同的值,因为 intval 参数被评估两次,因此执行 post-increment 运算符(++ )两次。你只能通过创建临时变量,为它们分配参数,并且永远不再提及参数来保证评估问题不会发生。

注意:如果您不能保证输出缓冲区有足够的 space 来保存结果,我会反对使用 strcpy字符串(加上 NULL 终止符)。

更新:

@Bill Lynch in comments, the version above may still put you in trouble if you have variables with the same names the macro uses internally. This is known as Variable Shadowing 所述。任何好的编译器都应该能够发出警告。例如,GCC 会警告您甚至在没有 -Wall-Wextra 的情况下进行编译。目前,我们能为宏做的最好的事情只是尝试通过在宏中为变量名添加前缀来尽量减少阴影的风险。这可能是一个很好的做法,但这不是真正的解决方案。这就是当时的样子:

#define DO_SOMETHING(buf, str) \
    do { \
        const char *DO_SOMETHING_in = str; \
        char *DO_SOMETHING_out = buf; \
        const size_t DO_SOMETHING_len = strlen(DO_SOMETHING_in); \
        strcpy(DO_SOMETHING_out, DO_SOMETHING_in); \
        write_strongswan_conf(DO_SOMETHING_out, DO_SOMETHING_len);
    } while (0)

一个好的建议是尽可能用适当的函数替换宏,避免宏的所有晦涩

在我看来,这段代码不需要调用宏。改为使用数组:

#include <stdio.h>

void write_strongswan_conf(const char *buffer)
{
    FILE *fp = fopen("strongswan.txt", "a");
    if (fp != 0)
    {
        fprintf(fp, "%s\n", buffer);
        printf("Data Written: %s\n", buffer);
        fclose(fp);
    }
}

int main(void)
{
    static const char *conf_string[] =
    {
        "STRONG SWAN CONFIGURATION FILE",
        "THIS IS THE SECOND LINE",
    };

    for (int i = 0; i < sizeof(conf_string) / sizeof(conf_string[0]); i++)
        write_strongswan_conf(conf_string[i]);

    return(0);
}

我很乐意假设每次写入字符串时打开和关闭文件是明智的。我不相信是这种情况,但原始代码做出了假设。 (打开一个文件相当昂贵;你不会无缘无故地这样做,这对我来说有点无缘无故。)

write_strongswan_conf() 函数中的代码使用 fprintf() 而不是 fwrite() 因为您只是在编写字符串,这样可以避免将换行符连接到缓冲区,并且因此减少了复制的数量。事实上,您甚至不需要知道字符串有多长; fprintf() 会为您数数。

结果代码中确实没有任何地方可以从转换为宏中获益;没有足够大的重复块。初始化的字符串数组可以占用 25 行,也可以占用 2 行。如果您愿意,写入函数可以与其他数据源一起使用。您可以从另一个文件中读取这些行,或者让用户键入它们,或者程序生成它们。它不受 1000 个字符的行限制(给定或接受 — 998 将是原始代码中字符串的最大安全长度)并且可以处理更长的行。它会错误检查 fopen() 调用,如果 fopen() 失败,它不会尝试使用空文件指针写入;避免崩溃。