简体   繁体   English

基于另一个变量设置一组变量的有效方法?

[英]Efficient way to set a group of variables based on another variable?

I'd like to set a group of 2-4 variables, their values dependent on a 5th variable. 我想设置一组2-4个变量,它们的值取决于第5个变量。 I can do it by a long list of if else , I was wondering if there was a trick I don't know about I could learn, to do it a little more elegantly? 我可以通过一长串的if else来做到这一点,我想知道是否有一个我不知道可以学到的技巧,可以更优雅地做到这一点? I'm still very new to ``C. 我对``C.

For example: 例如:

/*some code... x is read from stdin...*/

if (x == 1) {
  a = 10;
  b = 100;
}

else if (x == 2) {
  a = 10;
  b = 50;
  c = 100;
}

else if (x == 3) {
  a = 0;
  b = 25;
  c = 50;
  d = 100;
}
/* and so on...*/

I'm planning to do it all in a function away from main() using pointers to set a , b , c ... but I've omitted it here for simplicity. 我打算使用指针来设置abc ...,而不是通过main()函数来完成所有操作,但是为了简单起见,这里省略了它。

Cheers, 干杯,

W w ^

Well, a switch statement is generally more elegant than a bunch of if-else statements 好吧, switch语句通常比一堆if-else语句更优雅

switch (x) {
    case 1:    a = 10;
               b = 100;
               break;

    case 2:    a = 10;
               b = 50;
               c = 100;
               break;

    case 3:    a = 0;
               b = 25;
               c = 50;
               d = 100;
               break;

    default:   // have a default case or catch it as an error
}

And you could tighten the code a little more by using functions to set the variables, if you really care about keeping this section of code short and easy to read. 如果您真的很想让这段代码简短易读,则可以通过使用函数来设置变量来进一步加紧代码。

switch (x) {
    case 1:    caseA(&a, &b);
               break;

    case 2:    caseB(&a, &b, &c);
               break;

    case 3:    caseC(&a, &b, &c, &d);
               break;

    default:   // have a default case or catch it as an error
}

void caseA(int *a, int *b) {
    *a = 10;
    *b = 100;
}

You can use switch(x) which will allow you to recycle some code if a few values have identical effects. 您可以使用switch(x) ,如果一些值具有相同的效果,则将允许您回收某些代码。 For instance 例如

switch(x){
    case 5:
    case 6:
        a=0;
        b=25; //this code will run for both cases
}

with limitations of course. 当然有限制。 You can't really apply this to every case. 您不能真正将其应用于所有情况。

Also by using ternary operators you can handle some borderline cases. 同样,通过使用三元运算符,您可以处理一些临界情况。 Imagine for example a=10 every time except when x==2 , then it is 5 . 想象一下,例如,每次x==2a=10 ,那么它就是5。 Therefore you can handle that single variable like this: a = (x==2)?5:10; 因此,您可以像这样处理单个变量: a = (x==2)?5:10;

My way, for what it's worth which tractably separates the data from the program functionality: 以我的方式,将数据与程序功能区分开来的价值是:

int data[3][4] = {  
   {10, 100, 0, 0},
   {10, 50, 100, 0},
   {0, 25, 50, 100}
};

a , b , c , and d become a particular row of this array, which you index with abcd成为此数组的特定行,您可以使用该行对其进行索引

data[-1 + x]
static const int a[4] = {10, 10, 0};
static const int b[4] = {100, 50, 25};
static const int c[4] = {0, 100, 50};
static const int d[4] = {0, 0, 100};

printf("%d %d %d %d\n", a[x - 1], b[x - 1], c[x - 1], d[x - 1]);

or using Mathematics, and with specific values in mind: 或使用数学,并要牢记以下特定值:

// if (x == 1){a = 10; b = 100;}
// else if (x == 2){a = 10; b = 50; c = 100;}
// else if (x == 3){a = 0; b = 25; c = 50; d = 100;}

void get_values(int x, int *a, int *b, int *c, int *d)
{
   *a = (1 - x / 3) * 10;
   *b = 100 >> (x - 1);
   *c = (x - 1) * (200 >> (x - 1));
   *d = (x / 3) * 10;
}

int main(void)
{
    int a, b, c, d;
    int x = 3;

    get_values(x, &a, &b, &c, &d);
    printf("%d %d %d %d\n", a, b, c, d);
    return (0);
}

will usually be faster than all above solutions as compilers are not able to make these ultra specific optimizations but it depends on your needs. 通常将比上述所有解决方案都要快,因为编译器无法进行这些超具体的优化,但这取决于您的需求。 Also the last one, while being the fastest, will definitely hurt readability so you should keep computed values as comment. 同样,最后一个虽然最快,但肯定会损害可读性,因此您应将计算值保留为注释。

If the x values are actually sequential, then you can create an array of structs to hold the values for a,b,c,d. 如果x值实际上是连续的,则可以创建一个结构数组来保存a,b,c,d的值。 The only trick is that you need a sentinel value to indicate that a variable should not be set. 唯一的技巧是,您需要一个哨兵值来指示不应设置变量。 In the example below, a value of -1 is the sentinel value. 在下面的示例中,值-1是前哨值。

struct setting
{
    int a, b, c, d;
}
settings[] =
{
    {  0,   0,  0,    0 },     // x = 0 not used
    { 10, 100, -1,   -1 },     // -1 indicates that a variable should be skipped
    { 10,  50, 100,  -1 },
    {  0,  25,  50, 100 },
};
static int maxSetting = sizeof(settings) / sizeof(settings[0]);

void updateSettings(int x, int *a, int *b, int *c, int *d)
{
    if (x > 0 && x < maxSetting)
    {
        struct setting *sptr = &settings[x];
        if (sptr->a >= 0)
            *a = sptr->a;
        if (sptr->b >= 0)
            *b = sptr->b;
        if (sptr->c >= 0)
            *c = sptr->c;
        if (sptr->d >= 0)
            *d = sptr->d;
    }
}

If you feel like hacking you could do this fancy trick: 如果您想黑客入侵,可以尝试以下技巧:

typedef enum
{
    CASE_1_ = 1,
    CASE_2_,
    CASE_3_

}states;

void caseA(int *a, int *b, int *c, int *d) {
    *a = 10;
    *b = 100;
}

typedef void (*fp)(int *, int *, int *, int *);

fp proccess[] = {[CASE_1_] = caseA, [CASE_3_] = caseB, [CASE_3_] = caseC};

All you need to do is proccess[x](); 您需要做的只是proccess[x](); , and you won't need any switch or if-else statements. ,并且您不需要任何switchif-else语句。

Just for fun, if you want to complicate things for now, but make your life easier going ahead with multiple such scenarios, I have a solution which at first looks very ugly to implement, but I love the way it works in terms of scalability and re-usability. 只是为了好玩,如果您现在想使事情复杂化,但是在多种情况下使您的生活更轻松,我有一个解决方案,乍一看很难实施,但是我喜欢它在可伸缩性和可扩展性方面的工作方式。可重用性。

The code below works in an interactive way for testing purposes, discard whatever you feel unnecessary. 以下代码以交互方式用于测试目的,丢弃您认为不需要的所有内容。

#include<stdio.h>                                                                     

// Lets get handlers for each value                              
int f_One(void);
int f_Two(void);
int f_Three(void);
int f_Four(void);

// Lets have them in an enum rather than mere numbers, may not be required for you
typedef enum {

    ONE = 1,
    TWO,
    THREE,
    FOUR,

    MAX_TASKS,
    TASK_INVALID = -1,

} eValue_t ;

// This is a structure that binds an input and a handler together
typedef struct stTask {

    eValue_t TaskID;
    int (*handler) (void);

} stTask_t;

// Lets have an object
stTask_t Task;

// This is a like look-up table for referencing inputs and their handlers
const stTask_t TaskList[MAX_TASKS-1] =
{
    { ONE,    f_One   },
    { TWO,    f_Two   },
    { THREE,  f_Three },
    { FOUR,   f_Four  },
}; 

// This is your data
int a, b, c, d;

// Handler for 1
int f_One(void)
{
    printf("\nOne: ");
    a = 10;
    b = 100;
    printf("a is %d, b is %d", a, b);

    return 1;
}

// Handler for 2
int f_Two(void)
{
    printf("\nTwo: ");
    a = 10;
    b = 50;
    c = 100;
    printf("a is %d, b is %d, c is %d", a, b, c);

    return 2;
}

// Handler for 3
int f_Three(void)
{
    printf("\nThree: ");
    a = 0;
    b = 25;
    c = 50;
    d = 100;
    printf("a is %d, b is %d, c is %d, d is %d", a, b, c, d);

    return 3;
}

// Handler for 4
int f_Four(void)
{
    printf("\nFour: I didn't set any :D");
    return 4;
}

int main (void)
{
    int Val = -1;
    int ret = 0;

    while(1)
    {
        // Get input
        printf("\n\nPress 1, 2, 3, 4 or 0 for exit, Enter a value: ");
        scanf("%d", &Val);
        // Some validation, can be improved, or discarded
        if(Val > 4)
        {      
            printf("\nInvalid input");
            continue;
        }
        else if(Val == 0)
        {
            printf("\nExiting...");
            break;
        }
        // Assign the task
        Task.TaskID = Val-1;
        // Load the handler
        Task.handler = TaskList[Task.TaskID].handler;
        // Execute the handler
        ret = Task.handler();
        // Do something with 'ret'
    }
    printf("\n\n");
    return 0;
}

Yo can use union with enumeration. 可以将枚举与union使用。 Size of the structure always be the one of the biggest content structure tho. 结构的大小始终是最大的内容结构之一。

enum type
{
    BAR = 0,
    BAZ,
    OTHER,
};

struct bar
{
    int x;
    char y;
};

struct baz
{
    void * x;
    float y;
};

struct other
{
    char x[2];
};

typedef struct _foo
{
    enum type type;
    union
    {
        struct bar bar;
        struct baz baz;
        struct other other;
    };
} foo;

...

struct bar a = { 1, 'c', };

foo x;
x.type = BAR;
x.bar = a;


struct baz b = { NULL, 1.0f, };

foo y;
y.type = BAZ;
y.baz = b;

if (x.type == BAR)
    printf("%d\n", x.bar.x);

if (y.type == BAZ)
    printf("%p\n", y.baz.x);

Just for the sheer fun of it, you can use variadic functions. 仅出于纯粹的乐趣,您就可以使用可变参数函数。 Here is how one might do that (with usage example, you can easily put it into your if ladder): 这是一个可能的方法(通过使用示例,您可以轻松地将其放入if阶梯中):

#include <stdarg.h>
#include <stdio.h>

void set_bunch(int n_vars, ...) {
    va_list args;
    va_start(args, n_vars);
    for (int i = 0; i < n_vars; ++i) {
        int* varp = va_arg(args, int*);
        int varv = va_arg(args, int);
        *varp = varv;

    }
    va_end(args);
}

int main() {
    int a, b, c, d;

    set_bunch(2, &a, 20, &b, 30);
    printf("%d %d\n", a, b); // prints 20 30

    set_bunch(3, &a, 30, &b, 40, &c, 50);
    printf("%d %d %d\n", a, b, c); // prints 30 40 50
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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