宏来迭代结构成员

时间:2013-03-27 12:34:44

标签: c macros bit-fields

我使用位字段结构来访问像素中的每个颜色通道,问题是我经常以相同的方式对每个通道应用代码,但因为我不能只迭代结构的成员在CI中,每个成员最多有3个相同代码的副本,或者更不方便地使用switch-case语句。

我认为如果我可以使用一个宏来更优雅,这样我就可以通过提供一个数字来访问一个成员,理想情况下是一个可以使.CHAN(i)成为.r,.g或.b的宏。关于整数变量i是否包含0,1或2.除了我不知道如何制作这样的宏,或者即使这样也是可能的。

一个细节,但每个成员都是12位,而不是人们所期望的8,所以我不能把它变成一个数组或者有一个带指针的联合。此外,X-Macros不会这样做,因为在对另一个通道执行相同操作之前,我经常需要对每个通道执行很多操作,换句话说,遍历每个成员的for循环可以包含的不仅仅是一行。

编辑:这是一些代码,首先是结构:

typedef struct
{
    uint32_t b:12;
    uint32_t g:12;
    uint32_t r:12;
    uint32_t a:12;
} lrgb_t;

现在举例说明我的问题在代码中的样子:

for (ic=0; ic<3; ic++)
{
    for (i=0; i<curvecount; i++)
    {
        curve[i].p0.x = (double) i;
        curve[i].p3.x = (double) i+1.;

        switch (ic)     // this is what I'm trying to eliminate
        {
            case 0:
                curve[i].p0.y = pancol[i].r / 4095.;
                curve[i].p3.y = pancol[i+1].r / 4095.;
                break;
            case 1:
                curve[i].p0.y = pancol[i].g / 4095.;
                curve[i].p3.y = pancol[i+1].g / 4095.;
                break;
            case 2:
                curve[i].p0.y = pancol[i].b / 4095.;
                curve[i].p3.y = pancol[i+1].b / 4095.;
                break;
        }
        // Ideally this would be replaced by something like this, CHAN() being an hypothetical macro
        // curve[i].p0.y = pancol[i].CHAN(ic) / 4095.;
        // curve[i].p3.y = pancol[i+1].CHAN(ic) / 4095.;
    }

    ... // more stuff that ultimately results in a bunch of pixels being written, channel after channel
}

3 个答案:

答案 0 :(得分:2)

正如评论中指出的那样,这并没有真正解决OP的问题,因为他的结构上的成员是不能与数组对齐的位域。我会在这里保留答案,希望它对某人有用。

我认为union就是你想要的。 您可以编写结构,例如

union
{
   struct
   {
       float r;
       float g;
       float b;
   }rgb;
   float channel[3];
} color;

这样结构将与float [3]在内存中的相同位置,并且您可以有效地访问与结构成员相同的成员或作为数组中的元素。

您可能需要查找确切的语法,但您明白了。

答案 1 :(得分:1)

一种可能性是将重复的代码包装成一个函数,然后为每个通道调用它:

typedef struct {
  int r:12;
  int g:12;
  int b:12;
} Pixel;

int inc(int val) {
  return val + 1;
}

int main(void) {
  Pixel p = {0, 0, 0};
  p.r = inc(p.r);
  p.g = inc(p.g);
  p.b = inc(p.b);
  return 0;
}

答案 2 :(得分:0)

阅读您添加的代码后,我对建议的宏进行了一些更改

#define CHAN(ic) \
(ic == 1) ? curve[i].p0.y = pancol[i].r / 4095; curve[i].p3.y = pancol[i+1].r / 4095; : \
(ic == 2) ? curve[i].p0.y = pancol[i].g / 4095; curve[i].p3.y = pancol[i+1].g / 4095; : \
curve[i].p0.y = pancol[i].b / 4095; curve[i].p3.y = pancol[i+1].b / 4095;

宏CHAN(ic)将评估'ic'以决定操纵哪个成员。如果'ic'为1,则成员'.r'将被操纵,如果'ic'为2,那么'.g'将被操纵,如果'ic'既不是1或2,那么'.b'将被操纵,因为在这个假设中,你必须确保'ic'被正确设置,否则你可以使用panco [i] .b和pancol [i + 1] .b的值。您的代码应该类似于以下内容,但如果您有任何问题,您很可能需要稍微调整一下宏。

//#define CHAN(ic) here

for (ic=0; ic<3; ic++)
{
  for (i=0; i<curvecount; i++)
  {
     curve[i].p0.x = (double) i;
     curve[i].p3.x = (double) i+1.;
     CHAN(ic)
  }
  ... // more stuff that ultimately results in a bunch of pixels being written, channel after channel
}

另请注意,我的宏将与您的开关案例完全相同。唯一的区别是它是在宏中定义的,我试图做的是切换案例和宏之间的区别纯粹是可视化的。