3

As part of a struct(let's call it ASM) in a header file there are declared four uint32_t ints.

uint32_t Result1; 
uint32_t Result2; 
uint32_t Result3; 
uint32_t Result4; 

I want to access these like this: ASM->Result1, ASM->Result2 etc and combine them into one 128 bit int with Result1 being bits 0-31 from the left, so in the end I'd have:

return 128bitint = Result1Result2Result3Result4;

How can this be done?

Django
  • 343
  • 1
  • 4
  • 23
  • 1
    What data type should hold them? – edmz Feb 20 '16 at 17:53
  • 1
    even `unsigned long long` is only 64-bit I think... Perhaps you can consider using array of char t hold those results: `char a[16];` – Ian Feb 20 '16 at 17:55
  • 1
    There's a GCC extension which defines `__int128`, a 128-bit integer type that can also be unsigned. But, I don't know how portable this is or if OP has access to GCC. – SevenBits Feb 20 '16 at 18:01

2 Answers2

4

I'd use union:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(void) {
    union {
        struct {
            uint32_t v1;
            uint32_t v2;
            uint32_t v3;
            uint32_t v4;
        } __attribute__((packed));
        unsigned __int128 i128;
    } t128;
    t128.v1 = 0x22221111;
    t128.v2 = 0x44443333;
    t128.v3 = 0x66665555;
    t128.v4 = 0x88887777;

    printf("0x%016"PRIx64"%016"PRIx64"\n", (uint64_t)(t128.i128 >> 64), (uint64_t)t128.i128);

    return 0;
}

This gives:

0x88887777666655554444333322221111

as a result on intel (little-endian) architecture.

nsilent22
  • 2,763
  • 10
  • 14
  • @chqrlie: Of course, you are right. Fixed, thank you. – nsilent22 Feb 20 '16 at 18:29
  • Sorry, but I was not precise enough, `%lx` does not necessarily handle 64 bits (long is 32 bits on Windows even in 64 bit code). You must either use the `PRIx64` macros or use `llx` and cast the arguments as `(unsigned long long)`: `printf("0x%016"PRIx64"%016"PRIx64"\n", (uint64_t)(t128.i128 >> 64), (uint64_t)t128.i128);` or `printf("0x%016llx%016llx\n", (unsigned long long)(uint64_t)(t128.i128 >> 64), (unsigned long long)(uint64_t)t128.i128);` – chqrlie Feb 20 '16 at 18:36
  • @chqrlie: Oh, I didn't know about PRIx64 macro. How useful! Thank you once again. – nsilent22 Feb 20 '16 at 18:43
  • I am +1 ing because you mention endianness... I would just probably just return the struct for maximum portability, ie, don't worry about the union – Grady Player Feb 20 '16 at 18:45
  • Sadly the union trick is UB, and you're assuming no structure packing. An array of the 32 bit unsigneds and a memcpy is feasible. – Bathsheba Feb 20 '16 at 18:52
  • @Bathsheba: Packing added. – nsilent22 Feb 20 '16 at 19:38
  • Believe it or not, it's still UB! But perhaps bordering on pedantry. – Bathsheba Feb 20 '16 at 21:55
  • @Bathsheba: Well, of course you are right. But this UB is 100% DB on all platforms I know. – nsilent22 Feb 20 '16 at 22:09
  • @Bathsheba where is the UB? – M.M Feb 21 '16 at 06:47
1

You need support for 128 bit integers for this.

with gcc on appropriate platforms, you can write this:

__uint128_t getval(const struct ASM *s) {
    return ((__uint128_t)s->Result1 <<  0) |
           ((__uint128_t)s->Result2 << 32) |
           ((__uint128_t)s->Result3 << 64) |
           ((__uint128_t)s->Result4 << 96);
}

Note that it is unclear what you mean by Result1 being bits 0-31 from the left. To clarify your specification, you must decide it Result1 are the low order 32 bits (intel architecture, little endian, my code above), or the high order 32 bits (big endian architecture).

chqrlie
  • 131,814
  • 10
  • 121
  • 189