简体   繁体   中英

Look for an elegant way to declare an array of struct with strings in C

I'm trying do do something like what I've done in C++ with QT, in C. This is a part of the C++ code:

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}
};

I'm trying to make something similar in C. I know that i can do sometring like this:

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},
    ....
};

But this is not elegant and clear as the C++ way. My "mission" is to make or find a precompiler macro that make the code as much readable as possible.

Any suggestions?

Your current C code is wrong because, as it is, &s_00 is not a pointer-to-const-char ( const char* ) but a pointer-to-pointer-to-const-char ( const char** ), because s_00 is of type const char[] . Same for the others. So that must be fixed before making it look neat.

Additionally you cast the const away which is only 'safe' if you know that the pointed to memory will not be modified after all. If you do not need to modify your AT commands/repsonse, then they are effectively constant anyway and so you could simply use const char* for the relevant struct members throughout and use literals everywhere. By far the easiest solution, your code would look like this:

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}
};

If you do need to modify them (then your C++ code may not have worked properly either), you need to do something involving:

  1. malloc() / calloc() appropriate amount of memory first
  2. strncpy() the const char* literall into the newly allocated memory of the struct member
  3. when done, make sure to free() that memory again.

To give a toy example of how you could implement that:

#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;
}

As an aside: the reason your C++ code 'works' is that QString is a container with copy-on-write semantics (detaching), so you can safely pass it const char* and QString will copy it when needed. (Therefore no attempt will be made to write to the original const char* ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM