Reputation: 307
Basically I'm trying to remove duplicates in my code by using enum and a new function to help.
Say I have a structure with following:
typedef struct user {
bool empty;
int lineNumber;
char *errMessage;
char *username;
char *password;
char *uid;
char *gid;
char *gecos;
char *dir;
char *shell;
} user;
and I make an enum like the following:
typedef enum {username, password, uid, gid, gecos, dir, shell} userValue;
What I'm trying to do is send a parameter userValue enumParam
in a function and by that choose which member in the structure I want to access. Example of the helper function:
void parseHelper(userValue enumParam) {
user *newStruct;
newStruct -> enumParam = "hello";
}
Example of usage:
parseHelper(password)
Expected: newStruct->password should point to "hello"
But this isn't helping because I receive the following error:
'user {aka struct user}' has no member named 'val'
Upvotes: 1
Views: 144
Reputation: 179
The way I would go about this is using function pointers. It is not a very clean solution but it should work..
Basically in this solution the enums MUST be in the same order that the char pointers are defined in within the structure. (I would prefer setting them manually to the index in the struct like so:
typedef enum {
username = 0,
password = 1,
uid = 2,
gid = 3,
gecos = 4,
dir = 5,
shell = 6
} userValue;
Now the enum can be used as an index from the first char* represented by the enum in the structure (the username). This can be done by getting a pointer to the char* and increment it using pointer arithmetic.
Full code example (Used debugger to confirm correct execution):
#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;
}
-Edit
Maybe a more readable way of achieving the same result is to cast the first char*
(in this case the username) to an array of char*, and use the standard array syntax to move to the desired offset in the
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";
}
-- Option 2
If you are able to modify the structure definition, and nowhere else do you want to specifically access the strings by their name (for example user->username
), you can declare an array of char pointers in your struct like so:
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;
and then fill in as necessary using the index to array:
void parseHelper(userValue enumParam)
{
user newStruct;
memset(&newStruct, 0, sizeof(user));
newStruct.otherFields[enumParam] = "hello";
}
Under the hood, this solution is identical to the first one. However, this has the added benefit of simplifying the use of the enum to access the desired char*
, while loosing the benefit of using the string name to access a particular string in the rest of the code.
Upvotes: 1
Reputation: 4433
I have a proposal for you.
First, add a last item to your enum
list (userValue_max
):
typedef enum {username, password, uid, gid, gecos, dir, shell, userValue_max} userValue;
Now, define your struct
in a slightly different way, containing an array of strings:
typedef struct user
{
bool empty;
int lineNumber;
char *errMessage;
char *field[userValue_max];
} user;
Now write your code in this way:
void parseHelper(userValue enumParam) {
user *newStruct = malloc(sizeof(user)); // Allocating memory here!!
newStruct->field[enumParam] = "hello";
}
Upvotes: 2
Reputation: 753675
You can't do what you're trying to do as directly as you show because enumeration constants are names for integers, not names of structure members. You can't directly write a reference to a structure member using any sort of variable to identify the member name — you must explicitly name a member (so it is a hard-wired offset into the structure).
However, assuming you have C11 support in your compiler for anonymous union and structure members, and assuming that you can redefine the structure type (it isn't wholly fixed and immovable, pre-ordained by some exterior force, such as a tutor or a standard), you can get fairly close to what you want with code like this:
#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;
}
When run, it produces the output:
me:secret:0:1:Yours Truly:/home/me:/bin/sea
There are several factors that make this work.
char *
).If you're stuck with C90 or C99, you can achieve a similar effect, but it is more verbose:
#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;
}
This produces the same output, of course.
Upvotes: 0
Reputation: 405
-> operator is for accessing member variable of a pointer to a structure. Important thing is the names of these member variable can't vary. You should call them by whichever name you have given to them in the declaration.
Here you are trying to access member variable of name 'val', but there is no such member variable. Hence the error.
In this function you will have to put the possible values of enum under conditions to match possible names of structure.
Upvotes: 0
Reputation: 67476
No my friend.
Enums are just integers, they are no string substitutions :)
Upvotes: 3