【问题标题】:easy way to access union members访问工会成员的简单方法
【发布时间】:2015-07-17 15:30:00
【问题描述】:

我有一个里面有联合的结构体,如下图

typedef struct {
    Type_e type;
    union {
        char m_char;
        int m_int;
        // more types. over 27 types with special types
    } my_data;
} Data_t;

此结构用于开发算法,包括函数/方法内的奇异值分解 (SVD)。但是,每次我需要访问联合的元素时,我都必须使用 switch(超过 10 个 switch() 将用于 SVD)。根据我有限的理解,在每个实例中,所有工会成员都持有相同的价值。我可以使用 char 成员并将其转换为不同的类型吗?例如:

Data_t  lData; 
// initialize lData with some values

int x = (int)(lData.my_data.m_char).

以及这将如何用于转换指针?

即使使用强制转换,在某些情况下我仍然需要使用 switch。有没有办法避免使用开关?我尝试使用不同的 struct 格式(如 Declare generic variable type 中所述),看起来使用 union 更具可读性。以前,没想到就结束了:(

这个例子在上一篇文章中提到过,里面也有类似switch的例子

void vector(Data_t *vec, UInt32_t start_element, UInt32_t end_element)
{
    UInt32_t i;

    // check *vec is not null
    if (!vec) 
    {
        // Write error 
    }

     Data_t x;

    for (i =start_element; i <= end_element; i++)
    {
        switch (vec[i].type)
        {
        case UINT32: x.my_data.m_int = vec[i].my_data.m_int; break;
        // more possible cases
        default:
            break;
        }
    }
}

【问题讨论】:

  • 什么开关?能给我举个例子吗?我不清楚这个问题。
  • 你有这些结构/联合的数组吗?当其中 100 个具有相同类型时,您是否尝试更有效地访问它们?还是您想编写更简洁的代码? (也就是说,你是想优化计算机的时间,还是你的?)
  • @Eugene Sh,我添加了一个简单的例子,我正在研究的那个更复杂,需要算术运算(我不想让问题复杂化)
  • @SteveSummit 我正在尝试优化计算成本,同时使用有效的编码方式(对于 SVD 函数,我需要在三个嵌套的 for 中进行多个开关。如果这有意义:)
  • switch 嵌套在 for 内,嗯?知道了。看我的回答。

标签: c unions


【解决方案1】:

由于我刚加入 SO,我还没有添加 cmets 的声望。所以添加它作为答案:

据我所见,即使您想键入它,正如您在问题中所述,那么在该位置您已经知道它是哪种类型(int 或 char)。在这种情况下,您可以直接访问m_int,因此无需切换或强制转换。

因此,您要么遵循这种使用联合的方法,要么使用 other answer 中所述的 (void *)

【讨论】:

  • 结果变量的类型取决于输入的变量。我在想像 Data_t x 之类的东西; x.m_data.int = (vec[i].type)(vec[i].m_data.m_char)。但是再想一想,这看起来很愚蠢:(
  • 此外,或者只是覆盖结构中的 = 运算符,这将返回正确的返回值(所以我不需要每次使用 = 运算符时都使用 switch 复制代码)
【解决方案2】:

我认为没有什么聪明的方法可以比访问工会成员的官方、正常、可移植的方式更快。

听起来您正在内部循环中访问联合。如果你有类似的东西

for(i = 0; i < ni; i++) {
    for(j = 0; j < nj; j++) {
        for(k = 0; k < nk; k++) {
            switch(type) {
                case T_CHAR:
                    u[i][j][k].m_char = f(v[i][j][k].m_char);
                    break;
                case T_INT:
                    u[i][j][k].m_int = g(v[i][j][k].m_int);
                    break;

如果如图所示,type 的值没有改变,那么是的,您花费大量时间执行switch 语句,总共执行ni*nj*nk 次,而不是一次最好的。

加快速度的直接方法是将switch移到循环之外:

switch(type) {
    case T_CHAR:
        for(i = 0; i < ni; i++) {
            for(j = 0; j < nj; j++) {
                for(k = 0; k < nk; k++) {
                    u[i][j][k].m_char = f(v[i][j][k].m_char);
        } } } break;

    case T_INT:
        for(i = 0; i < ni; i++) {
            for(j = 0; j < nj; j++) {
                for(k = 0; k < nk; k++) {
                    u[i][j][k].m_int = g(v[i][j][k].m_int);
        } } } break;
}

当然,这里最大的缺点是,对于每种类型,循环遍历代码都被复制了 N 次。因此,挑战在于找到一种方法来最小化这项工作,特别是如果代码可能会更改并且您不想在所有 N 个地方都更改它。

如果您遇到这种情况,我们可以更具体地说明如何以更简洁的方式实现高效代码。 (例如,我曾经使用一些预处理器技巧将循环代码复制 N 次。)

【讨论】:

    【解决方案3】:

    首先,请记住 char 通常是 8 位,而 int 通常是 32 位。(“典型地”在可移植性中是一个麻烦)。

    但是,如果您有足够大的数据类型来容纳您想要的任何种类,是的,您可以在技术上将变量转换为类型重要的每次交互时所需的类型。对于一个数学重的图书馆来说,这可能很多。在每次交互中,您都需要一个 switch 语句将其转换为正确的类型,因此您并没有真正获得任何东西。

    工会的众多转换可能会很痛苦,但这可能是最好的方法。它确实避免了为所有 10 种数据类型复制所有这些代码。

    Google 在 C 中进行泛型编程。有些人尝试过使用函数指针和宏的替代方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-24
      • 2016-05-18
      • 1970-01-01
      • 2015-04-22
      • 1970-01-01
      • 1970-01-01
      • 2012-10-10
      相关资源
      最近更新 更多