C使用枚举来缩短代码

时间:2017-09-02 16:57:29

标签: c enums

基本上我正试图通过使用枚举和新功能来帮助删除代码中的重复项。

假设我有以下结构:

typedef struct user {
    bool empty;
    int lineNumber;
    char *errMessage;
    char *username;
    char *password;
    char *uid;
    char *gid;
    char *gecos;
    char *dir;
    char *shell;
} user;

我做了如下的枚举:

typedef enum {username, password, uid, gid, gecos, dir, shell} userValue;

我要做的是在函数中发送参数userValue enumParam,然后选择我想要访问的结构中的哪个成员。辅助函数示例:

void parseHelper(userValue enumParam) {
    user *newStruct;
    newStruct -> enumParam = "hello";
}

使用示例:

parseHelper(password)

Expected: newStruct->password should point to "hello"

但这没有帮助,因为我收到以下错误:

  

'user {aka struct user}'没有名为'val'的成员

5 个答案:

答案 0 :(得分:3)

不,我的朋友。

枚举只是整数,它们没有字符串替换:)

答案 1 :(得分:2)

我有一个建议给你。

首先,将最后一项添加到enum列表(userValue_max):

typedef enum {username, password, uid, gid, gecos, dir, shell, userValue_max} userValue;  

现在,以稍微不同的方式定义您的struct,包含一个字符串数组:

typedef struct user
{
    bool empty;
    int lineNumber;
    char *errMessage;
    char *field[userValue_max];
} user;  

现在以这种方式编写代码:

void parseHelper(userValue enumParam) {
    user *newStruct = malloc(sizeof(user)); // Allocating memory here!!
    newStruct->field[enumParam] = "hello";
}  

答案 2 :(得分:1)

我将采用的方法是使用函数指针。它不是一个非常干净的解决方案,但应该有效..

基本上在这个解决方案中,枚举必须与在结构中定义char指针的顺序相同。 (我更喜欢手动将它们设置为结构中的索引,如下所示:

typedef enum {
    username = 0, 
    password = 1,
    uid = 2,
    gid = 3,
    gecos = 4,
    dir = 5,
    shell = 6
} userValue;

现在,枚举可以用作结构中枚举的第一个char *的索引(用户名)。这可以通过获取指向char *的指针并使用指针算法递增它来完成。

完整代码示例(使用调试器确认正确执行):

#include <string.h>

typedef struct user
{
    bool empty;
    int lineNumber;
    char *errMessage;
    char *username;
    char *password;
    char *uid;
    char *gid;
    char *gecos;
    char *dir;
    char *shell;
} user;

typedef enum { 
    username = 0,
    password = 1,
    uid = 2,
    gid = 3,
    gecos = 4,
    dir = 5,
    shell = 6
} userValue;

void parseHelper(userValue enumParam)
{
    user newStruct;
    memset(&newStruct, 0, sizeof(user));

    char** selected = &newStruct.username;
    selected = (char**)(selected + ((int)enumParam));
    *selected = "hello";
}

int main()
{
    parseHelper(username);
    parseHelper(password);
    parseHelper(uid);
    parseHelper(gid);
    parseHelper(gecos);
    parseHelper(dir);
    parseHelper(shell);
    return 0;
}

<强> - 编辑 也许更可读的方法是实现相同的结果是将第一个char*(在本例中为用户名)转换为char *数组,并使用标准数组语法移动到

void parseHelper(userValue enumParam)
{
    user newStruct;
    memset(&newStruct, 0, sizeof(user));

    // Other fields is an array of char * which starts at username...
    char** otherFields = &newStruct.username;
    otherFields[(int)enumParam] = "hello";
}

- 选项2

如果您能够修改结构定义,并且您想要通过其名称专门访问字符串(例如user->username),您可以在结构中声明一个char指针数组,如此:

typedef struct user
{
    bool empty;
    int lineNumber;
    char *otherFields[7];
    // otherFields[0] - username
    // otherFields[1] - password
    // otherFields[2] - uid
    // otherFields[3] - gid
    // otherFields[4] - gecos
    // otherFields[5] - dir
    // otherFields[6] - shell
} user;

然后根据需要使用索引到数组填写:

void parseHelper(userValue enumParam)
{
    user newStruct;
    memset(&newStruct, 0, sizeof(user));

    newStruct.otherFields[enumParam] = "hello";
}

在引擎盖下,此解决方案与第一个解决方案相同。但是,这样做的另一个好处是简化了使用枚举来访问所需的char*,同时失去了使用字符串名来访问其余代码中的特定字符串的好处。

答案 3 :(得分:0)

- &GT; operator用于访问指向结构的指针的成员变量。重要的是这些成员变量的名称不能改变。你应该在宣言中用你给他们的名字来称呼他们。

在这里,您尝试访问名称&#39; val&#39;的成员变量,但没有这样的成员变量。因此错误。

在此函数中,您必须在条件下放置枚举的可能值以匹配可能的结构名称。

答案 4 :(得分:0)

由于枚举常量是整数的名称,而不是结构成员的名称,因此您无法像显示的那样直接执行您尝试执行的操作。您不能使用任何类型的变量直接写入对结构成员的引用来标识成员名称 - 您必须明确地命名成员(因此它是结构中的硬连线偏移量)。

但是,假设您的编译器对匿名联合和结构成员有C11支持,并假设您可以重新定义结构类型(它不是完全固定且不可移动的,由某些外力预先规定,例如作为导师或标准,你可以通过这样的代码得到你想要的东西:

#include <stdio.h>
#include <stdbool.h>

typedef struct user
{
    bool empty;
    int lineNumber;
    char *errMessage;
    union
    {
        struct
        {
            char *username;
            char *password;
            char *uid;
            char *gid;
            char *gecos;
            char *dir;
            char *shell;
        };
        char *field[7];
    };
} user;

typedef enum {username, password, uid, gid, gecos, dir, shell} userValue;

static void parseHelper(user *u, userValue enumParam, char *value)
{
    u->field[enumParam] = value;
}

int main(void)
{
    user u;
    u.empty = false;
    u.lineNumber = 1;
    u.errMessage = "no error";
    parseHelper(&u, password, "secret");
    parseHelper(&u, username, "me");
    parseHelper(&u, uid, "0");
    parseHelper(&u, gid, "1");
    parseHelper(&u, gecos, "Yours Truly");
    parseHelper(&u, dir, "/home/me");
    parseHelper(&u, shell, "/bin/sea");

    printf("%s:%s:%s:%s:%s:%s:%s\n", u.username,
           u.password, u.uid, u.gid, u.gecos, u.dir, u.shell);
    return 0;
}

运行时,它会产生输出:

me:secret:0:1:Yours Truly:/home/me:/bin/sea

有几个因素可以使这项工作。

  1. 结构成员名称位于不同的名称空间中,因此枚举元素名称不会干扰结构成员名称。
  2. 您尝试处理的所有字段都属于同一类型(char *)。
  3. 如果在结构中有匿名联合,则可以按名称访问联合的元素。
  4. 如果联合中有匿名结构,则可以按名称访问结构中的元素。
  5. 如果你坚持使用C90或C99,你可以达到类似的效果,但它更加冗长:

    #include <stdio.h>
    #include <stdbool.h>
    
    typedef struct user
    {
        bool empty;
        int lineNumber;
        char *errMessage;
        union
        {
            struct
            {
                char *username;
                char *password;
                char *uid;
                char *gid;
                char *gecos;
                char *dir;
                char *shell;
            } f;
            char *field[7];
        } u;
    } user;
    
    typedef enum {username, password, uid, gid, gecos, dir, shell} userValue;
    
    static void parseHelper(user *u, userValue enumParam, char *value)
    {
        u->u.field[enumParam] = value;
    }
    
    int main(void)
    {
        user u;
        u.empty = false;
        u.lineNumber = 1;
        u.errMessage = "no error";
        parseHelper(&u, password, "secret");
        parseHelper(&u, username, "me");
        parseHelper(&u, uid, "0");
        parseHelper(&u, gid, "1");
        parseHelper(&u, gecos, "Yours Truly");
        parseHelper(&u, dir, "/home/me");
        parseHelper(&u, shell, "/bin/sea");
    
        printf("%s:%s:%s:%s:%s:%s:%s\n", u.u.f.username, u.u.f.password,
               u.u.f.uid, u.u.f.gid, u.u.f.gecos, u.u.f.dir, u.u.f.shell);
        return 0;
    }
    

    当然,这会产生相同的输出。