【问题标题】:Look for an elegant way to declare an array of struct with strings in C寻找一种优雅的方式来用 C 中的字符串声明一个结构数组
【发布时间】:2017-05-20 15:41:13
【问题描述】:

我正在尝试在 C 中使用 QT 在 C++ 中做类似的事情。 这是 C++ 代码的一部分:

typedef struct {
    int     order;
    int     type;
    QString cmd;
    QString res[2];
    double  timeout;
    int     exitAfterNChar;
}atCmdList_t;
atCmdList_t atCmdList[] = {
    {0,0, "ATI", {"", ""}, 1, -1},
    {0,0, "AT+GSN", {"", ""}, 1, -1},
    {0,0, "AT+COPS?", {"+COPS: 0,0,\"vodafone IT\",2", ""}, 1, -1}
};

我正在尝试用 C 语言制作类似的东西。 我知道我可以这样做:

const char s_00[]  = {""};
const char s_01[]  = {"ATI"};
const char s_02[]  = {"AT+GSN"};
const char s_03[]  = {"AT+COPS?"};

typedef struct {
    int     order;
    int     type;
    const char *  cmd;
    const char *  res[2];
    double  timeout;
    int     exitAfterNChar;
} atCmdList_t;
atCmdList_t atCmdList[] = {
    {0,0, s_01, {s_00, s_00}, 1, -1},
    {0,0, s_02, {s_00, s_00}, 1, -1},
    ....
};

但这不像 C++ 方式那样优雅和清晰。 我的“任务”是制作或找到一个使代码尽可能具有可读性的预编译器宏。

有什么建议吗?

【问题讨论】:

    标签: c arrays string coding-style


    【解决方案1】:

    您当前的 C 代码是错误的,因为事实上,&s_00 不是指向 const-char (const char*) 的指针,而是指向指向 const-char 的指针 (const char** ),因为 s_00 的类型为 const char[]。其他人也一样。所以在让它看起来整洁之前必须解决这个问题。

    此外,如果您知道指向的内存毕竟不会被修改,那么您将const 强制转换为“安全”。如果您不需要修改您的 AT 命令/repsonse,那么它们无论如何都是有效的,因此您可以简单地将 const char* 用于整个相关的结构成员,并在任何地方使用文字。到目前为止,最简单的解决方案是您的代码如下所示:

    typedef struct {
      int     order;
      int     type;
      const char* cmd;
      const char* res[2];
      double  timeout;
      int     exitAfterNChar;
    } atCmdList_t;
    
    atCmdList_t atCmdList[] = {
      {0,0, "ATI", {"", ""}, 1, -1},
      {0,0, "AT+GSN", {"", ""}, 1, -1},
      {0,0, "AT+COPS?", {"+COPS: 0,0,\"vodafone IT\",2", ""}, 1, -1}
    };
    

    如果您确实需要修改它们(那么您的 C++ 代码也可能无法正常工作),您需要执行以下操作:

    1. malloc()/calloc()先适量内存
    2. strncpy()const char*literall 进入结构成员新分配的内存
    3. 完成后,请确保再次free() 该内存。

    举一个玩具例子来说明如何实现它:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    struct Foo 
    {
      char * data;
    };
    
    char * copy_static_string(const char* src, size_t sz) 
    {
      if(src) 
      {
        char * dst = malloc(sz);
        return dst ? strncpy(dst, src, sz) : NULL;
      }
      else 
      {
        return NULL;
      }
    }
    
    #define COPY_STATIC_STRING(x) (copy_static_string((x), sizeof(x)))
    
    int main()
    {
      struct Foo foo = { .data = COPY_STATIC_STRING("hello, world!") };
      printf("%s\n", foo.data); // check .data != NULL, don't forget!
      free(foo.data); // don't forget to clean up, either!
      return 0;
    }
    

    顺便说一句:您的 C++ 代码“工作”的原因是 QString 是一个具有写时复制语义(分离)的容器,因此您可以安全地传递它 const char* 并且 QString 将在需要时复制它. (因此不会尝试写信给原来的const char*)。

    【讨论】:

    • 对不起,我没有检查、控制或编译C代码。 :) 我的错。但感谢您的提示,尤其是指出 C++ 代码中的错误。也许我没有正确地写这个问题,因为我的要求是寻找更好和最清晰的方法来用 C 编写这种类型的 C++ 代码,只是为了让它尽可能地可读。
    • @user11804 我已经给出了替代方法的玩具示例。
    • 感谢您的回复。这是一个好方法,但是,我的错,我没有提到我正在为只有几 kb 内存的 arm 处理器编写代码。对于具有大量内存的系统(例如 pc 或运行 linux 的板)来说,这是一个很好的选择。就我而言,malloc 的使用不是很好。最好的办法是将字符串直接写入微处理器的闪存中,并仅在需要时将一些 memcpy 写入 ram 缓冲区。这就是为什么我想使用预处理器宏而不是在运行时将字符串放在 ram 上的函数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-20
    相关资源
    最近更新 更多