how to assign 64 bit unsigned long long to 32 bit

2019-08-14 04:08发布

I have 2 cores, one is 32 bit and other is 64 bit.

On 64 bit machine, I have support for unsigned long long, and I need to assign this value to a varriable which will be access in 32 bit machine, such as:-

typedef struct {
    unsigned int low;
    unsigned int high;
} myint64_t;

myint64_t app_sc;

Below is the code snippet for 64 bit machine:

unsigned long long sc;

/* Calculate sc */
...

Now on 64 bit machine, I need to assign "sc" to app_sc, and use it for some computing on 64 bit machine.

I was trying to do something like this:-

app_sc = sc;

but compiler gives me compile time errors. I can similarly do, something like this:-

 app_sc.low = sc & 0xFFFFFFFF;
 app_sc.high = (sc>>32) & (0xFFFFFFFF);

But does that guarantee, it will work in all cases?

Is there any better way of doing it?

5条回答
我欲成王,谁敢阻挡
2楼-- · 2019-08-14 04:30

Firstly, I agree with the suggestion of using the stdint types if possible, so I'll do so myself.

Secondly, the only possibly cheaper way I can think of to do the conversion is via a union, like

union Int64
{
    uint64_t val64;
    struct {
        uint32_t lo32;
        uint32_t hi32;
    };
};

union Int64 i64;
i64.val64 = sc;
app_sc.low = i64.lo32;
app_sc.high = i64.hi32;

Caveats

  • if doing this involves a store and re-load (as shown), it may well be more expensive than your bit-wise operations
    • if you can convert your existing app_sc into an instance of this union (skipping the 32-bit loads), then it might be worthwhile
  • alternatively, if sc is already genuinely stored somewhere in memory, and you can just cast its address to (union Int64 *)
    • of course, if sc is currently allocated a register and is dirty, taking the address might force a store anyway
  • in principle there could be packing & alignment issues, either now or with some subsequent ABI
  • this is architecture-dependent, so a subsequent port could mean changing the union (I'm assuming x86 little-endianness above)

Frankly it's fragile, as I hope the caveats show. Still, it's another way of doing it, and you can decide whether it's also better in your case.

查看更多
孤傲高冷的网名
3楼-- · 2019-08-14 04:37

You can use header file stdint.h for using signed/unsigned variable uint64_t/int64_t/...uint8_t/int8_t for better explanation : http://pubs.opengroup.org/onlinepubs/007904975/basedefs/stdint.h.html

查看更多
劳资没心,怎么记你
4楼-- · 2019-08-14 04:40

By 32 and 64 bit architecture the thing which change is the size of pointer so unsigned long long will work in the same way in 32 as it worked in 64 bit.

查看更多
干净又极端
5楼-- · 2019-08-14 04:44

With a not too old compiler supporting a reasonably recent C standard (probably C99, perhaps even earlier) you should have a <stdint.h> header giving you a type like int64_t (for a signed 64 bits integer) or uint64_t (for an unsigned 64 bits integer) which is exactly 64 bits, even on 32 bits machine.

If your compiler don't have it, I strongly suggest to upgrade your compiler. You could probably use GCC (except if you have a very strange target architecture, unsupported by GCC). Latest GCC version is 4.7.

Notice that 64 bits arithmetic on 32 bits machines needs in practice some compiler support to be reasonably efficient. (e.g. to use add with carry instructions). It can't be done only thru a library, even if a library is required to supply the most complex operations (e.g. 64 bits divisions on 32 bits machines). In other words, fast 64 bits arithmetic can't be portably coded in C for a 32 bits machine.

For much bigger numbers, consider using arbitrary precision numbers (called bigints), e.g. thru the GNU gmp library. Such libraries uses non-trivial algorithms (so even the math is quite difficult, you can read entire books on them and earn a PhD by inventing a competitive bigint implementation).

查看更多
手持菜刀,她持情操
6楼-- · 2019-08-14 04:54

Your compiler, even on the 32 bit machine, may support "long long int". Try it?

查看更多
登录 后发表回答