1

I'm attempting to implement a protocol standard and I'm having a bit of trouble with their concept of conditional fields. They are defined as fields that are present or absent depending on some condition. The example they give is as follows:

    uint16 Pressure;
    enum VehicleType { car = 0, motorbike = 1};
    struct TirePressureInfo {
                    VehicleType type;
                    select (type)
                    {
                    case car:
                            Pressure frontLeft;
                            Pressure frontRight;
                            Pressure rearLeft;
                            Pressure rearRight;
                    case motorbike:
                            Pressure front;
                            Pressure rear;
                    }
            }

I'm unaware of anyway to make this work in C, or if it's even possible. I can't think of anyway to implement this. One thing to note, is this is going to be implemented in a Linux Kernel Module, so I'm a bit restricted there as well.

            struct {
                    uint8 protocol_version;
                    ContentType type;
                    select (type) {
                    case unsecured :
                    opaque data<var>;
                    case signed, signed_partial_payload,
                    signed_external_payload:
                    SignedData signed_data;
                    case signed_wsa:
                    SignedWsa signed_wsa;
                    case encrypted :
                    EncryptedData encrypted_data;
                    case crl_request :
                    CrlRequest crl_request;
                    case crl :
                    Crl crl;
                    case other_value:
                    opaque data<var>;
                    }
            } 1609Dot2Data;




    struct {
            SignerIdentifierType type;
            select (type) {
            case self: ;
            case certificate_digest_with_ecdsap224 :
            case certificate_digest_with_ecdsap256 :
                    HashedId8 digest;
                    opaque data<var>;
            case certificate:
                    Certificate certificate;
            case certificate_chain:
                    Certificate certificates<var>;
            case certificate_digest_with_other_algorithm :
                    Signer signer;
                    PKAlgorithm algorithm;
                    HashedId8 digest;
            case other_value:
                    opaque id<var>;
            }
    } SignerIdentifier;
Seechay
  • 23
  • 4
  • 2
    I think you're looking for a [`union`](http://stackoverflow.com/questions/252552/why-do-we-need-c-unions). – e0k Jan 30 '16 at 21:03
  • 1
    Either union or an uber-structure containing all possible fields. There is no such thing as a conditional field in C. – Jim Buck Jan 30 '16 at 21:05
  • Unions are just representing data in different ways, right? I need different fields contained in the structure, not just different ways of representing them. – Seechay Jan 30 '16 at 21:06
  • Well, Google is your friend with finding out how to use unions, but basically they just are a way of re-interpreting the same area of memory. It saves from wasting memory for fields that aren't used depending on your vehicle type, but it's only a concern is you are on a platform that could benefit from the memory savings (and how many structures for tire pressure info you will have). – Jim Buck Jan 30 '16 at 21:09
  • 1
    If you refuse using a `union`, your question is not clear. Using different fields at the same time means you need a `struct`. – too honest for this site Jan 30 '16 at 21:10
  • The pressure was just an example given by IEEE. The actual structure will contain fields of different data types. I'm updating the question with their required data type. – Seechay Jan 30 '16 at 21:11
  • Still a `union`. The fields in each of the cases can be represented by a seperate member within the one `union`. – kaylum Jan 30 '16 at 21:14
  • I don't think I can use a union. There are instances where there's not just one field associated with the condition. It can be 3 different types of variables inside, so like signed_wsa would contain an int, double and float. encrypted_data would contain just int and double. How can I accomplish that with a union? – Seechay Jan 30 '16 at 21:22
  • `signed_wsa` would be a struct. Which is a perfectly valid type for a union member. That is, a struct within a union within a struct. – kaylum Jan 30 '16 at 21:22
  • Oh my! Think recursive! – too honest for this site Jan 30 '16 at 21:23
  • 1
    Well worth looking at Neil Brown's kernel design patterns articles on LWN eg) https://lwn.net/Articles/446317/ discusses data structures for file systems, which like motorbikes & car's may have common parts and specialised. It may be better to have a car, which embeds a vehicle struct, rather than have vehicle with union of car/bike. – Rob11311 Jan 30 '16 at 21:24
  • @kaylum What about when each type requires a different number of fields? – Seechay Jan 30 '16 at 21:25
  • You can have a `union` of `struct`s. – e0k Jan 30 '16 at 21:27
  • Each union member can be a struct and each struct has different fields. – kaylum Jan 30 '16 at 21:28
  • I understand I can have a union of structs. It seems as if everyone is ignoring the part where I mentioned that the select won't have the same number of fields for each case. Some could be just a single field, other cases it could be ten. I can't figure out how to do a case like that with a union. – Seechay Jan 30 '16 at 21:28
  • I'm adding another example. – Seechay Jan 30 '16 at 21:29
  • That new example doesn't change the principle. It just means you have another union inside your `SignerIdentifier` struct. – kaylum Jan 30 '16 at 21:31

1 Answers1

7

You can use a union:

uint16 Pressure;
enum VehicleType { CAR = 0, MOTORBIKE = 1};
struct TirePressureInfo {
  VehicleType type;
  union {
    struct {
      Pressure frontLeft;
      Pressure frontRight;
      Pressure rearLeft;
      Pressure rearRight;
    } car;
    struct {
      Pressure front;
      Pressure rear;
    } motorbike;
  } data;
};

So then you can set it like:

struct TirePressureInfo info;
info.type = CAR;
info.data.car.frontLeft  = 35;
info.data.car.frontRight = 35;
info.data.car.rearLeft   = 32;
info.data.car.rearRight  = 32;

or if you want to define a MOTORBIKE:

struct TirePressureInfo info;
info.type = MOTORBIKE;
info.data.motorbike.front = 38;
info.data.motorbike.rear  = 40;

When you read from it, you should check the type:

switch ( info.type ) {
case CAR:
    /* read info.data.car fields */
    break;
case MOTORBIKE:
    /* read info.data.motorbike fields */
    break;
default:
    /* Some data integrity problem */
}

If you are certain that you only ever need a struct car or struct motorbike at a time (depending on the value of type), then there is no need to waste space by having every TirePressureInfo include both struct car's fields and struct motorbike's fields. Using a union makes the struct car and struct motorbike occupy the same place in memory. The actual size of the union is the greater of the two. This just gives you different ways to read and write to the same place in memory.

Community
  • 1
  • 1
e0k
  • 6,961
  • 2
  • 23
  • 30
  • That makes a lot more sense to me. It's a bit difficult trying to visualize it, as I have very little experience with unions. – Seechay Jan 30 '16 at 21:34