【问题标题】:Regarding C typedef struct关于 C typedef struct
【发布时间】:2013-06-25 21:36:06
【问题描述】:

我有多个 typedef struct box 实例,所以 box box1、box box2 等。 结构的成员是长度、宽度、高度等。

typedef struct 
{
    int width;
    int height;
} box;

box box1;
box box2;

如何创建一个对每个宽度成员进行操作的函数 盒子实例?我的困惑是如何将指针传递给 typedef 结构成员 适用于所有盒子实例。我知道如何将指针传递给特定的 像 box1.width 这样的实例成员,但是如何传递 .width 然后做

box1.width=value;
box2.width=value;
box3.width=value;

在函数内?

【问题讨论】:

  • 你不能。没有全局变量。但不要打扰。
  • typedef 只为结构提供新名称。没有什么可以用它做的。
  • 为什么不使用数组? SetWidth(size_t arraySize, box array[], int desiredWith)?
  • C++ 有一个称为 pointer-to-member 的功能,它允许您在没有实例的情况下形成指向结构成员的指针,例如int box::*ptr = &box::width; box1->ptr = value; box2->ptr = value;。但是 C 没有这个特性,所以如果你不能使用 C++,那么你将不得不使用提供的替代答案之一。

标签: c struct


【解决方案1】:

您可能需要考虑使用数组而不是大量单独的实例,例如

typedef struct 
{
    int width;
    int height;
} Box;

Box boxes[3];                   // array of 3 boxes

for (b = 0; b < 3; b++)         // set `width` field of all boxes to `value`
    boxes[b].width = value;

或者,如果您出于某种原因确实想要迭代多个不同的框变量,那么您可以初始化一个指针数组,例如

 Box box1;  // 3 separate Box variables
 Box box2;
 Box box3;

 Box *boxes[3] = { &box1, &box2, &box3 };
                                 // array of pointers to box1, box2, box3

 for (b = 0; b < 3; b++)         // set `width` field of all boxes to `value`
    boxes[b]->width = value;

【讨论】:

  • 我建议选择创建一个指针数组,以防您想要迭代现有的框。
  • @Elazar:好点子 - 问题不是很清楚,所以我将其添加为选项。
  • 我实际上正在做的是将实例结构成员值存储到 eeprom。我只是想编写一个函数,可以将每个实例中的所有相同成员存储在一起。感谢所有的建议。我会试一试。
【解决方案2】:

typedef(或结构)中没有字段width 可以附加指针。该场仅在物理上存在于该类型的具体对象中。所以,你不能有一个指向结构的width 的指针。您只能拥有指向box1.widthbox2.width 等的指针。

不可能以某种方式编写一个函数来更改所有现有对象中的width。更准确地说,不可能编写一个函数以某种方式神奇地枚举该类型的所有现有对象并更改其中的字段width。您有责任告诉您的函数您要更改哪些对象。

无论如何,你想做什么?


如果您正在尝试编写一个“setter”函数,该函数将使用要设置的特定字段进行运行时参数化,如果可以通过偏移量在 C 中完成。例如

void set_value(box *box, size_t offset, int value) {
  *(int *) ((char *) box + offset) = value;
}

box box1;
box box2;
box box3;

void set_values(size_t offset, int value)
{
   set_value(&box1, offset, value);
   set_value(&box2, offset, value);
   set_value(&box3, offset, value);
}

正在调用

set_values(offset_of(box, width), 42);

在调用时将box1box2box3 中的宽度设置为42

set_values(offset_of(box, height), -5);

将这些对象的高度设置为-5

但是,您有责任确保函数知道它必须更改哪些对象。在上面的示例中,我只是将它们声明为文件范围变量。在现实生活中,这通常是不可能的。

【讨论】:

  • 我不推荐像*(int *) ((char *) box + offset) 这样的类型双关语,因为有违反严格别名规则的风险
  • @Joe:这里没有类型双关语。将int 对象作为int 对象访问并不构成类型双关语。通过相当复杂的指针算法执行访问这一事实并没有改变它。
  • 直到有人有使用该函数设置浮动成员的好主意(不是任何人都应该......)
【解决方案3】:

您似乎在要求指向成员的指针,但是这些是 C++ 功能(可以使用 offsetof 模拟它们,尽管您可能会遇到严格的别名问题)。除非您要求的.width 会影响box所有 个实例,但没有指定具体实例。在这种情况下,没有答案。这看起来像这样:

// C++ ahead

struct box
{
    int width;
    int height;
};

box boxes[3];

void setGlobalBoxesValue(int value, int box::*member)
{
    for(unsigned int i = 0; i < sizeof(boxes)/sizeof(boxes[0]); ++i)
        boxes[i].*member = value;
}

int main(int, char**)
{
    setGlobalBoxesValue(4, &box::width);
    setGlobalBoxesValue(3, &box::height);
    return 0;
}

邪恶的Coffsetofvariant:

// C emulation (not typesafe)

#include <stddef.h>
#include <string.h>

typedef struct
{
    int width;
    int height;
} box;

box boxes[3];

void setGlobalBoxesValue(int value, size_t memberOffset)
{
    for(unsigned int i = 0; i < sizeof(boxes)/sizeof(boxes[0]); ++i)
        memcpy((char*)(boxes+i) + memberOffset, &value, sizeof(value));
}

int main(int, char**)
{
    setGlobalBoxesValue(4, offsetof(box, width));
    setGlobalBoxesValue(3, offsetof(box, height));
    return 0;
}

如果您只想对 box 的多个实例应用相同的操作,请将它们放在一个数组中并循环遍历该数组(如果它们分布在内存中,则为指针数组)。

【讨论】:

    【解决方案4】:

    我不确定我是否理解你的问题,但是

    如何创建一个对所有宽度成员进行操作的函数 每个盒子实例?我的困惑是如何将指针传递给 typedef 结构成员,适用于 box 的所有实例。我知道 如何将指针传递给特定的实例成员,如 box1.width 但是如何传递.width然后做

    通过创建一个以 typedef 作为参数的函数,您可以访问结构的宽度

    void foo(box* p)
    {
      p->width  .. do something
    ...
    } 
    

    或者如果你的意思是传递一个盒子数组

    void foo(box* p, int count)
    { 
      for (int i = 0; i < count; ++i)
      {
         p[i]->width .. do something
        ...
      }
    }
    

    【讨论】:

      【解决方案5】:

      您不能将width 字段本身传递给函数。但是,您可以在结构内传递它的偏移量。这是一个“肮脏”的技巧,有时用于低级编程,但我不建议您在没有充分理由的情况下使用它。

      另一种选择是使用宏。这也可能是个坏主意,但方法如下:

      #define assign(field, value) \
          do { \
              box1.field = value; \
              box2.field = value; \
              box3.field = value; \
          } while (0) 
      

      并像这样使用它:

      assign(width, 5);
      

      如果你事先不知道这些盒子是什么,你可以结合这里建议的数组解决方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多