2

Sometimes, I need to declare a type, that works similar to a simple type, that may have a larger size than the register of a cpu, in some machines, in others not.

For example, a UUID (128 bits) or a (128 bits) datetime, in a 32 bits or 64 bits machine.

In some cases, there already are multiplatform libraries, but, in another doesn't.

I know is recommended to stick to existing libraries, but, in case that doesn't, how should I do ?

Example:

typedef
  uint_16 /* redeclare as */ code16;
  uint_32 /* redeclare as */ code32;

// option 1
struct code64
{
  packed uint_32 A, B;
};

// option 2
struct code64
{
  aligned uint32_t A, B;
};

// option 3
typedef
  packed uint_16 code64[4];

void Example( )
{ 
  code64 A = Foo();
  code64 B = Bar();
  code64 Q = Zaz(A, B);
}

As the tags indicates, I want it to be compiled, both, in "C" and "C++".

I already search for this subject in other questions, on stackoverflow.

umlcat
  • 4,091
  • 3
  • 19
  • 29
  • 12
    If your compiler doesn't provide a 128-bit integer type (like GCC and others do on some platforms), there is no way to create something that behaves like a new, larger, arithmetic type in C. In C++, you could create a class, and define operator overrides for it that allow it to behave like a larger integer type. This is what is being done in [this project](https://github.com/calccrypto/uint128_t#uint128_t). Please specify which language you are using, [tag:c] and [tag:c++] are not the same. – Thomas Jager Aug 13 '19 at 16:11
  • @Thomas Jagger I want to interact with both "c" and "c++" – umlcat Aug 13 '19 at 16:24
  • @umlcat: I think yours is a fair question (I even upvoted it). But a C++ solution will likely be radically different than a C solution (with the understanding that a "C" solution should be compatible to both). – paulsm4 Aug 13 '19 at 16:33
  • 3
    I don't think that `packed` and `aligned` are valid C++ keywords. – Walter Aug 13 '19 at 16:44
  • 1
    @KonradRudolph The question has been edited after I wrote my first comment. – user7860670 Aug 13 '19 at 16:46
  • 5
    Your requirements "similar to a simple type" and "interact with C" are mutually exclusive. You could get closer with C++, but will still have oddities compared to simple types. – Eljay Aug 13 '19 at 16:55
  • @KonradRudolph I edited the question (rephrase) as VTT indicates, to correct it. – umlcat Aug 13 '19 at 17:14
  • Not sure I understand the question. Are you looking for this, basically: https://stackoverflow.com/questions/4306186/structure-padding-and-packing – Nikos C. Aug 13 '19 at 17:24
  • Are you looking to do any operations other than assignment? I think the code you have would work fine for assignment. – Mark Ransom Aug 13 '19 at 17:28
  • @Mark Random as operators, Assignment, Equality, mostly user defined functions. I like to make udf before overloaded operators, and keep a func version of operator with unique id – umlcat Aug 14 '19 at 15:15

1 Answers1

2

A struct works like a simple type for the purpose of passing it around, taking its address, sizeof, etc. To just store some unstructured data inside, make a struct that contains a single array field.

typedef struct {
    uint8_t a[16];
} code128;

Depending on what you want to store, you may want to put more structure in your struct. For example, a UUID is formally defined as having fields of a certain size, some of which are stored in platform endianness. (However not all software cares about endianness, and modern software often treats UUIDs as just a bunch of bytes.)

typedef struct {
    uint32_t time_low;
    uint16_t time_mid;
    uint16_t time_hi_and_version;
    uint8_t clock_seq_hi_and_res;
    uint8_t clock_seq_low;
    uint8_t node[6];

For a 128-bit time, what this could be depends on how the time is counted. It's common to represent time as a 64-bit number of seconds and a number of fractions such as nanoseconds or 2^64th of a second. For example, modern Unix systems have this type:

typedef struct timeval {
    uint64_t tv_sec;
    uint64_t tv_usec;
};

You can't do arithmetic on these structures, but arithmetic is meaningless on UUID anyway, and arithmetic on time is usually not direct arithmetic because time with subsecond precision is usually not represented as a single number.

If you do need arithmetic, some platforms offer uint128_t, but that's not portable (any C or C++ implementation must offer an integer type that's at least 64 bits, but they don't have to go beyond that). For example GCC and Clang both offer double-width integer types, so they offer uint128_t on machines where the CPU has 64-bit registers, but only up to uint64_t on 32-bit CPUs.

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
  • I prefer to use a user defined data type independent of other fields on a structure. The question also applied to typed different than UUID – umlcat Aug 14 '19 at 15:19
  • This is literally the purpose of a UDT. Are you encountering some practical problem with these common techniques, @umlcat? – Lightness Races in Orbit Aug 14 '19 at 15:27
  • @Lightness I see this particular case, as a very uncommon case, I declare a lot of user defined typed, that are larger, than CPU register, but, never had one, than required to be used as a simple type – umlcat Aug 14 '19 at 15:31
  • How is this an uncommon case? It describes literally every UDT every created. That's what a UDT _is_. It sounds like you need to do a little more research! – Lightness Races in Orbit Aug 14 '19 at 15:40
  • @umlcat I don't understand. What do you mean by “independent of other fields on a structure”? What do you mean by “required to be used as a simple type”? – Gilles 'SO- stop being evil' Aug 14 '19 at 17:06
  • @Gilles some of the types I want to implement, are number-alike, but, doesn't necessarily, require arithmetic, like add or subtract, or less or greater, maybe are equal or not. – umlcat Aug 16 '19 at 15:44