0

I have a struct with union inside it, as shown below

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

This struct is used to develop algorithms, including singular value decomposition (SVD) inside a function/method. However, every-time I need to access an element of the union, I have to use switch (over 10 switch() will be used for SVD). based on my limited understanding, at each instance of time, all union members hold the same value. Can I use the char member and cast it to the different types? For example:

Data_t  lData; 
// initialize lData with some values

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

and How will this work for casting pointers?

even with casting, I still needs to use switch in some cases. is there a way to avoid using switch? I tried using different struct format (as explained in Declare generic variable type ), and it looks using union is more readable. Previously, I didn't think is over :(

this example was mentioned in previous post, which has a similar example of 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;
        }
    }
}
Community
  • 1
  • 1
ras red2004
  • 169
  • 1
  • 1
  • 10
  • What switch? Can you give an example? The problem is not clear to me. – Eugene Sh. Jul 17 '15 at 15:31
  • 1
    Do you have an array of these structures/unions? When 100 of them have the same type, are you trying to access them more efficiently? Or are you trying to write code that's more concise? (That is, are you trying to optimize the computer's time, or yours?) – Steve Summit Jul 17 '15 at 15:52
  • @Eugene Sh, I added a simple example, the one i am working on is more complicated and requires arithmetic operations ( I did not want to complicate the question) – ras red2004 Jul 17 '15 at 17:02
  • @SteveSummit I am trying to optimize the computational cost while using efficient way of coding (for the SVD function, i need multiple switch inside three nested for . If that make sense :) – ras red2004 Jul 17 '15 at 17:05
  • `switch` inside nested `for`, eh? Got it. See my answer. – Steve Summit Jul 18 '15 at 00:57

3 Answers3

2

Since I just joined SO, I don’t have reputations to add comments yet. So adding it as answer:

From what I see, even if you want to type cast it, as you have stated in the question, then in that position you would already know which type it is (int or char). In that case, then you can directly access the m_int and hence there is no need for switch or cast.

So either you follow this approach of using a union or using the (void *) as noted in the other answer

Community
  • 1
  • 1
Sundar
  • 1,691
  • 1
  • 14
  • 20
  • the type of the resulting variable is dependent on the input one. I was thinking of something like Data_t x; x.m_data.int = (vec[i].type)(vec[i].m_data.m_char). But on a second thought, that's look foolish :( – ras red2004 Jul 17 '15 at 17:26
  • Furthermore, or just overriding = operator in the struct, which will return the correct return (so i don't need to duplicate the code with switch everytime i do = operator ) – ras red2004 Jul 17 '15 at 17:35
1

I don't think there's any clever way of accessing the member of the union that would be any faster than the official, normal, portable way of accessing the members of the union.

It sounds like you're accessing the union in an inner loop. If you have something like

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;

and if, as shown, the value of type doesn't change, then yes, you're spending a lot of time performing the switch statement a total of ni*nj*nk times instead of the one time you'd optimally want.

The straightforward way of speeding this up is to move the switch outside of the loops:

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;
}

Of course, the huge disadvantage here is that you've got the loop-traversal code replicated N times, for each of your types. So the challenge is to find a way of minimizing that work, especially if the code might change and you don't want to have to change it in all N places.

If this is the situation you're up against, we can be more specific about how to achieve the efficient code in a way that's cleaner. (For example, I once used some preprocessor tricks to replicate the loop code N times.)

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
0

First off, remember that a char is typically 8 bits, while an int is typically 32. ("Typically" as in portability is a pain in the ass).

But if you have a big enough data type to hold whatever variety you want, yes you could technically cast the variable to the desired type at every interaction where the type matters. Which is probably a lot for a mathmatics-heavy library. And at each interaction, you'd need a switch statement to cast it to the correct type, so you're not really gaining anything.

The numerous switches for a union may be a pain, but it might be the best way. It DOES avoid having to duplicate all this code for all 10 data types.

Google around for generic programming in C. Some people have tried alternatives with function pointers and macros.

Philip
  • 1,539
  • 14
  • 23