Is there a way (in C) to write a construct like the switch statement, but for strings? Is there a way to write a C construct at all in C?
By C construct I mean a statement with braces ... like an if statement has braces, and it's a C construct... right?
The simplest approach is an if-else chain using strcmp to do the comparisons:
if (strcmp(str, "String 1") == 0)
// do something
else if (strcmp(str, "String 2") == 0)
// do something else
else if (strcmp(str, "String 3") == 0)
// do something else
...
else
printf("%s not found\n", str);
A more complicated approach is to use a lookup table, keyed by the string:
struct lookup {const char *key; int value};
struct lookup LookupTable[] = {
{"String 1", 1},
{"String 2", 2},
{"String 3", 3},
...
{NULL, -1}
};
int lookup(const char *key)
{
size_t i = 0;
while (LookupTable[i].key != NULL)
if (strcmp(str, LookupTable[i].key) == 0)
return LookupTable[i].value;
else
i++;
return -1;
}
...
switch(lookup(str))
{
case 1: ...
case 2: ...
case 3: ...
...
default: printf("%s not found\n", str); break;
}
If you want to get really fancy, you could modify the lookup table so that the value is a pointer to a function:
void String1Cmd(void) { ... }
void String2Cmd(void) { ... }
void String3Cmd(void) { ... }
...
void BadCmd(void) { printf("Key not found!\n"); }
struct lookup {char *key, void (*cmd)(void); };
struct lookup LookupTable[] = {
{"String 1", String1Cmd},
{"String 2", String2Cmd},
{"String 3", String3Cmd},
...
{NULL, BadCmd}
};
void (*lookup(const char *str))(void)
{
size_t i = 0;
while(LookupTable[i].key != NULL)
if (strcmp(str, LookupTable[i].key) == 0)
return LookupTable[i].cmd;
else
i++;
return BadCmd;
}
...
void (*f)(void) = lookup(str); // retrieve the function for the given string
f(); // execute the function
In the last example, if str == "String 1", then String1Cmd will be executed. If str is a string not found in the lookup table, then BadCmd will be executed. This method is very flexible, and depending on your design, allows you to add behavior at runtime (sort of a plug-in architecture).
However, note that we've just deferred the main problem - branching on a string value - to the lookup function, and that the lookup function is back to just doing strcmp against each value in the table. We could speed that part of the process up by using a hash table or a tree to minimize the number of comparisons. Depending on how many strings you're branching on, that may or may not be worth the additional effort.
No, you have to do it yourself. There are many variants:
if (strcmp(str, "toto") == 0)
{
// ...
}
else if (strcmp(str, "tata") == 0)
{
// ...
}
else
{
// ...
}
If the number of strings is expected to grow, then a dispatch table with function pointers
struct dispatch_entry
{
const char *key;
void (*action)(void);
};
// Make sure it is sorted !
dispatch_entry dispatch_table[] =
{
{ "tata", &action_tata },
{ "toto", &action_toto },
};
coupled with binary search:
int dispatch_compare(const void *x, const void *y)
{
const dispatch_entry *xx = x, *yy = y;
return strcmp(xx->key, yy->key);
}
// Return -1 on failure
int dispatch(const char *str)
{
static const size = sizeof(struct dispatch_entry);
static const n = sizeof(dispatch_table) / size ;
dispatch_entry tmp = { str, NULL };
dispatch_entry *what = bsearch(tmp, dispatch_table, n, size, &dispatch_compare);
if (what == NULL) return -1;
(*what->action)();
return 0;
}
will do. Hash table based approaches are OK as well.
if you have the function lfind in your lib (POSIX or gcc) you can use it like:
enum { NOTFOUND, HELLO, WORLD, FOO, BAR };
char list[][100]={"hello","world","foo","bar"};
size_t r, siz = sizeof*list, num = sizeof list/siz;
char *tosearch = "foo";
switch ( (r=lfind(tosearch,list,&num,siz,strcmp))?
(r+siz-(size_t)list)/siz:0 ) {
case HELLO: puts("hello");break;
case WORLD: puts("world");break;
case FOO: puts("foo"); break;
case BAR: puts("bar"); break;
case NOTFOUND:puts("not found");
}
each string in the array must have the same size and should not be a pointer
a hashtable if you have a large number of strings and speed is an issue
No, since the switch may only be used with integral types, or a type convertible to an integral type
No, switch works on an integer value (I think floats/doubles are not even allowed). You can emulate that with if/else if/else doing strcmp.
if (strcmp(mystr, "this") == 0) {
//mystr == "this"
}
else if (strcmp(mystr, "that") == 0) {
//mystr == "that"
}
else {
//mystr is not "this" or "that"
}
Yes, and the way is - long if-else-if statement. (for reference: Why switch statement cannot be applied on strings? )
And what do you mean by "a C construct at all in C" o.O ? I'll edit my post, when you answer :)
Sure, depending on how much work you are willing to do.
You can use a preprocessor and some macros to map strings to integral identifiers, giving you a syntax like:
switch (SOSID_LOOKUP (sample_string)) {
case SOSID (hello): printf ("Hello "); break;
case SOSID (world): printf ("World! "); break;
case 0: default: printf ("unknown "); break;
}
If you can use C++ instead of C, you can use litb's template-based string switcher, giving you syntax like:
sswitch(s) {
scase("foo"): {
std::cout << "s is foo" << std::endl;
break; // could fall-through if we wanted
}
// supports brace-less style too
scase("bar"):
std::cout << "s is bar" << std::endl;
break;
// default must be at the end
sdefault():
std::cout << "neither of those!" << std::endl;
break;
}
Related
I have several struct declared which contain different data. I also have an enum that corresponds to those structures. There are several places in my code where I need to access information about the structures and I'm doing it via the enum. This results in few switch statements that return this information.
I've enclosed those switch statements in their own functions in order to re-use wherever possible. This resulted in three functions that look very similar.
Example psuedo-code:
#include <stdio.h>
typedef struct
{
int varA;
char varB;
} A;
typedef struct
{
int varA;
int varB;
int varC;
} B;
typedef struct
{
int varA;
short varB;
} C;
typedef enum { structA, structB, structC } STRUCT_ENUM;
int returnSize(STRUCT_ENUM structType)
{
int retVal = 0;
switch(structType)
{
case structA:
retVal = sizeof(A);
break;
case structB:
retVal = sizeof(B);
break;
case structC:
retVal = sizeof(C);
break;
default:
break;
}
return retVal;
}
void printStructName(STRUCT_ENUM structType)
{
switch(structType)
{
case structA:
printf("Struct: A\r\n");
break;
case structB:
printf("Struct: B\r\n");
break;
case structC:
printf("Struct: C\r\n");
break;
default:
break;
}
}
void createDataString(STRUCT_ENUM structType, char* output, unsigned char* input)
{
switch(structType)
{
case structA:
{
A a = *(A*)input;
sprintf(output, "data: %d, %d", a.varA, a.varB);
break;
}
case structB:
{
B b = *(B*)input;
sprintf(output, "data: %d, %d, %d", b.varA, b.varB, b.varC);
break;
}
case structC:
{
C c = *(C*)input;
sprintf(output, "data: %d, %d", c.varA, c.varB);
break;
}
default:
break;
}
}
int main(void) {
char foobar[50];
printf("Return size: %d\r\n", returnSize(structA));
printStructName(structB);
C c = { 10, 20 };
createDataString(structC, foobar, (unsigned char*) &c);
printf("Data string: %s\r\n", foobar);
return 0;
}
Those free functions basically contain the same switch with different code placed in the cases. With this setup, adding new struct and enum value results in three places in the code that needs changing.
The question is: is there a way to refactor this into something more maintainable? Additional constraint is that the code is written in C.
EDIT: online example: http://ideone.com/xhXmXu
You can always use static arrays and use STRUCT_ENUM as the index. Given the nature of your functions, I don't really know if you would consider it more maintainable, but it's an alternative I usually prefer, examples for names and sizes:
typedef enum { structA, structB, structC, STRUCT_ENUM_MAX } STRUCT_ENUM;
char *struct_name[STRUCT_ENUM_MAX] = {[structA] = "Struct A", [structB] = "Struct B", [structC] = "Struct C"};
size_t struct_size[STRUCT_ENUM_MAX] = {[structA] = sizeof(A), [structB] = sizeof(B), [structC] = sizeof(C)};
for printing content you can keep a similar array of functions receiving a void * that will print the value of this argument.
Edit:
Added designated initializers as per Jen Gustedt's comment.
You can make it into a single function and a single switch, with an additional parameter. Like so
int enumInfo(STRUCT_ENUM structType, int type) // 1 = returnSize 2 = printStructName
{
int retVal = 0;
switch(structType)
{
case structA:
If ( type == 1 ) { retVal = sizeof(A); }
else { printf("Struct: A"); }
break;
case structB:
If ( type == 1 ) { retVal = sizeof(B); }
else { printf("Struct: B"); }
break;
case structC:
If ( type == 1 ) { retVal = sizeof(C); }
else { printf("Struct: C"); }
break;
default:
break;
}
return retVal;
}
Could some give me a hint at this problem :
An expression is correct only if it contains parentheses and braces properly closed and no other character, even space. For example, () ({} () ({})) is a correct expression, whereas ({)} is not a correct expression or {} ({})). An empty expression (which does not contain any character) is correct.
Given a string expression determine if the expressions is correct and if is determine the maximum level of nesting. Maximum level of nesting parentheses is the maximum number of one another.
Examples
{}({}){{(({}))}}
answer : 5
{}({})) -1 (because the expression is incorrect)
That's what I've did so far.
#include <stdio.h>
#include <stdlib.h>
FILE *fi, *fo;
int first, er;
void X();
void Y();
void S() {
X();
Y();
}
void X() {
if(first=='{') {
first=fgetc(fi);
X();
if(first=='}')
first=fgetc(fi);
else
er=1;
S();
}
}
void Y() {
if(first=='(') {
first=fgetc(fi);
Y();
if(first==')')
first=fgetc(fi);
else
er=1;
S();
}
}
int main()
{
fi = fopen("brackets.in","r");
fo = fopen("brackets.out","w");
first=fgetc(fi);
S();
if(first!='\n')
er=-1;
fprintf(fo,"%d",er);
fclose(fi);
fclose(fo);
return 0;
}
First off, it helps to think of your problem as a formal grammar.
S = The Language you are testing for
S->
NUL // Empty
SS // S followed by itself.
[ S ] // Case 1
( S ) // Case 2
{ S } // Case 3
Since this grammar only has one symbol (S), you only need one parsing method.
The following code is incomplete but hopefully it gets the idea across.
char curr_char;
int main (void)
{
curr_char = getc();
result = parse_s();
return 0;
}
// Parse the S pattern off input. When this method completes, curr_char points to the character AFTER S.
// Returns recursion count or -1 on fail.
int parse_s()
{
max_count = 0;
while(true)
{
int curr_count = 0;
switch 'curr_char':
{
case '[': // [
int count = parse_s(); // S
if (count == -1) return -1; // The S must be valid
if (curr_char != ']') return -1; // ]
curr_char = getc(); // Advance past the ]
curr_count = count + 1; // This expression is 1 nest greater than its contained S
break;
case '(':
// XXX
break;
case '{':
// XXX
break;
default:
// This is either the SS (find the max of the two), the NUL case (return 0), or an error (return -1)
break;
}
// In the SS case you're gonna have to loop and do something here.
}
return max_count;
}
I have a pretty complex problem about c function pointers and passing the parameters to them.
I have a function pointer and a couple of function addresses within a lookup table. I get all of my data via a serial interface. First the number of the function which has to be called. I look it up in the table and pass the reference to my function pointer.
After that, i receive several pairs of 4 byte values as data as the arguments. Problem is, i have to call different functions with the same return type but a different amount of parameters.
Is there a way to pass dynamically data to a function call. Maybe by pushing them on the stack manually? Couldn't find a solution for that.
Does anybody has any idea or a hint to solve that problem?
I don't believe there's an easy way to answer this since argument passing is ABI (Application Binary Interface) specific. If your platform is fixed and you don't mind writing non-portable code then you can write your code in an ABI specific way but I wouldn't advise that.
I've solved this issue in a small emulator I wrote, for me it was easier since the number of commands was never greater than 4, I basically used a union of function pointers which had the number of arguments I wanted and a switch statement to select the right one.
typedef struct
{
union
__attribute__((__packed__))
{
void *func;
void (*func_a0)(void);
uint32_t (*func_a0r)(void);
void (*func_a1)(uint32_t);
uint32_t (*func_a1r)(uint32_t);
void (*func_a2)(uint32_t, uint32_t);
uint32_t (*func_a2r)(uint32_t, uint32_t);
void (*func_a3)(uint32_t, uint32_t, uint32_t);
uint32_t (*func_a3r)(uint32_t, uint32_t, uint32_t);
void (*func_a4)(uint32_t, uint32_t, uint32_t, uint32_t);
uint32_t (*func_a4r)(uint32_t, uint32_t, uint32_t, uint32_t);
};
unsigned args;
bool ret;
const char* name;
} jump_entry_t;
bool jump_table_exec(
jump_table_t* table, void* addr,
uint32_t* args, uint32_t* ret)
{
#ifdef JUMP_TABLE_DEBUG
if (!table)
return false;
#endif
if ((uintptr_t)addr < (uintptr_t)table->base)
return false;
unsigned i = ((uintptr_t)addr - (uintptr_t)table->base);
if ((i & 4) || (i >= table->size))
return false;
jump_entry_t j = table->entry[i >> 3];
if (!j.func)
return false;
if (j.args && !args)
return false;
if (j.ret)
{
if (!ret) return false;
switch (j.args)
{
case 0:
*ret = j.func_a0r();
break;
case 1:
*ret = j.func_a1r(args[0]);
break;
case 2:
*ret = j.func_a2r(args[0], args[1]);
break;
case 3:
*ret = j.func_a3r(args[0], args[1], args[2]);
break;
case 4:
*ret = j.func_a4r(args[0], args[1], args[2], args[3]);
break;
default:
return false;
}
}
else
{
switch (j.args)
{
case 0:
j.func_a0();
break;
case 1:
j.func_a1(args[0]);
break;
case 2:
j.func_a2(args[0], args[1]);
break;
case 3:
j.func_a3(args[0], args[1], args[2]);
break;
case 4:
j.func_a4(args[0], args[1], args[2], args[3]);
break;
default:
return false;
}
}
#ifdef JUMP_TABLE_DEBUG
if (j.name)
{
fprintf(stderr, "Info: Jump table %s(", j.name);
if (j.args >= 1) fprintf(stderr, "%" PRIu32, args[0]);
if (j.args >= 2) fprintf(stderr, ", %" PRIu32, args[1]);
if (j.args >= 3) fprintf(stderr, ", %" PRIu32, args[2]);
if (j.args >= 4) fprintf(stderr, ", %" PRIu32, args[3]);
fprintf(stderr, ")");
if (j.ret) fprintf(stderr, " returned %" PRIu32, *ret);
fprintf(stderr, ".\n");
}
#endif
return true;
}
Sometimes the following approach using unions is useful:
union foo {
struct {
int arg1;
} f1_args;
struct {
int arg1, arg2;
} f2_args;
};
int f1(union foo*);
int f2(union foo*);
int (*table[])(union foo*) = {f1, f2};
//...
union foo data;
//...
int answer = table[1](&data); // calls f2, which uses arg1 and arg2
And, if you prefer, f1 and f2 can be simple wrappers to the "real" functions, as in:
int f1(union foo *u) { return f1_real(u->f1_args.arg1); }
int f2(union foo *u) { return f2_real(u->f2_args.arg1, u->f2_args.arg2); }
This is quite flexible. But if your arguments are always only 4-byte ints, then you can get rid of the union and just use arrays. Rewritten, the above becomes:
int f1(uint32_t *a) { return f1_real(a[0]); } // wrapper
int f2(uint32_t *a) { return f2_real(a[0], a[1]); } // wrapper
int (*table[])(uint32_t *) = {f1, f2}; // lookup table
//...
uint32_t data[99]; // data from e.g. serial port
//...
int answer = table[1](data); // calls f2, which uses two args
Since the functions can distinguish their parameters, you can always give them a ... type. For example:
int f(...)
{
/* extract one int */
}
int g(...)
{
/* extract two floats */
}
...
int (*fp)(...);
if (type_one)
fp(10);
else if (type_two)
fp(1.3, 4.3);
Or better yet use a union. However, in your particular case, since the parameters themselves are "pairs of 4 bytes", you can always use an array:
struct arg
{
uint32_t pair_of_4_bytes[2];
};
int f(struct arg *args, size_t count)
{
}
int g(struct arg *args, size_t count)
{
}
...
int (*fp)(struct arg *args, size_t count);
struct arg args[MAX];
size_t count = 0;
/* get args from serial and put in args/count */
fp(args, count);
I think "Variadic functions" can solve your problem needs. Checkout a simple example here:
http://www.gnu.org/software/libc/manual/html_node/Variadic-Example.html#Variadic-Example
I have the following if-statements:
if (strcmp(registerName, "zero"))
return 00000;
else if (strcmp(registerName, "at"))
return 00001;
else if (strcmp(registerName, "v0"))
return 00010;
else if (strcmp(registerName, "v1"))
return 00011;
It's actually really long - about 20 if-statements. Therefore, I would like to use a switch. How would I convert that to switch when each statement has a different condition?
I tried something as the code below, but it does not work:
int registerAddress;
switch(registerAddress) {
case 1 (strcmp(registerName, "zero")):
regsiterAddress = 00000;
break;
case 2 (strcmp(registerName, "at")):
registerAddress = 00001;
break;
}
You can't — switch statements in C only work on primitive types, not on strings. You could use, say, a hash table or a search tree to optimize the matching, but for only 20 options that may not be worth the trouble.
What you could do, to clean up the code, is set up a mapping table:
struct str2Num {
char *str;
int num;
};
const struct str2Num registerMap[] = {
{ "zero", 00000 },
{ "at", 00001 },
{ "v0", 00010 },
{ "v1", 00011 },
{ NULL, 0 } /* end marker */
};
and do your matching like this:
int i;
for (i = 0; registerMap[i].str != NULL; i++) {
if (strcmp(registerName, registerMap[i].str) == 0) {
return registerMap[i].num;
}
}
/* handle no-match case here */
In fact, if you sorted the table alphabetically, you could even use bsearch() for fast matching.
You can only switch on integers, so this will not work.
If all you're doing is converting a string to an int, store the info in an array and look through it.
struct {
const char *name;
int value;
} fooMapping[] = {
{"zero",0},
{"at",1}
....
};
int foo2value(const char *name)
{
size_t i;
for(i = 0; i < sizeof fooMapping/sizeof fooMapping[0]; i++) {
if(strcmp(name, fooMapping[i].name) == 0)
return fooMapping[i].value;
}
return -1;
}
In a switch,
switch(number) {
case 1;
case 2;
case 7;
}
you are basically saying, if number = 1, then case 1. If number = 7, case 7. So what you need to do is assign each text value, in your case "zero""at""v0" and "v1", you would need to put these into an array, and in the switch statement, instead of switch(number) you would switch an integer that would correspond with the index number of whichever text you had. So if array[3] was = "v0", you would assign an integer to the index number (3) and then switch(integer). Hope this helped.
Why not use the ? operator like so:
return
strcmp(registerName, "zero")? 00000:
strcmp(registerName, "at") ? 00001:
strcmp(registerName, "v0") ? 00010:
strcmp(registerName, "v1") ? 00011:
...
Since switch-case only works with numbers or single chars, I would use a tool like GNU's gperf to create a perfect hash and switch on that value (followed by a strcmp() to be certain of an exact match). That ought to give you the desired performance improvement.
I am working on certain script language. Values containing structure is
struct myvar
{
char name[NAMELEN];
int type;
void* value;
}
type = 0 --> int* value
type = 1 --> char* value
type = 2 --> float* value
I faced some problem with arithmetic operations. It seems that I need to commit all sorts of type conversions over every single operation, that develops into writing a whole bunch of code for each of them, as in:
case 0: // "="
if(factor1.name)
{
if((factor1.type == 1) && (factor2.type==1))
{
free(factor1.value);
int len = (strlen((STRING)factor2.value)+1)*sizeof(char);
factor1.value = malloc(len);
memcpy(factor1.value,factor2.value,len);
}
else if((factor1.type == 2) && (factor2.type==2))
*(FLOAT*)factor1.value = *(FLOAT*)factor2.value;
else if((factor1.type == 0) && (factor2.type==0))
*(INTEGER*)factor1.value = *(INTEGER*)factor2.value;
else if((factor1.type == 0) && (factor2.type==2))
*(INTEGER*)factor1.value = *(FLOAT*)factor2.value;
else if((factor1.type == 2) && (factor2.type==0))
*(FLOAT*)factor1.value = *(INTEGER*)factor2.value;
else
GetNextWord("error");
}
break;
Is there some way to avoid this tiresome procedure? Otherwise I have no choice but to copy-paste this piece of code for each of "=","~","+","-","*","/","%",">","<",">=","<=","==","~=","AND","OR"
Use a union instead of a struct for the values:
struct myvar {
enum {
STRING, INT, FLOAT,
} type;
union {
char strval[NAMELEN];
int intval;
float fltval;
} val;
};
and then in executing the assignment operator in your scripting language you just do:
factor1 = factor2;
To fetch the right value based on the type you would do:
switch (operand.type) {
case STRING:
printf("%s", operand.val.strval);
break;
case INT:
printf("%d", operand.val.intval);
break;
case FLOAT:
printf("%f", operand.val.fltval);
break;
}
What about writing 3 toType functions:
char* toType0(myvar* from)
{
if (from->type == 0) return (char*)(from->value);
else if (from->type == 1) return itoa((int*)from->value);
else...
}
int toType1(myvar* from)
{
//convert to int...
}
Then in your conversion routines you can do:
switch (factor1.type)
{
case 0:
{ char* other = toType0(&factor2);
//assign or add or whatever....
};
break;
case 1:
{ int other = toType1(&factor2);
//assign or add or whatever....
};
break;
...
}
I would propose the following: when applying an operation, you should first coerce the operand types. E.g., if your operand types are int and float, you should coerce int value to a float one, and continue with the float version of the operation. The coercion is the same (or almost the same) for all the operations. With such an approach, you have much less cases to consider.