BItwise Operation ...

L

loudking

Hello, all.

I am not good at bitwise operation, so I wonder if some experts could
do me a help.

In a.c, somebody defined
================================================
# define u_int64 unsigned long long
# define u_short unsigned short
# define u_int unsigned int

u_short txid_slt;
u_int txid_sqn;

u_int64 tx_id= ((u_int64)txid_slt << 32) | (u_int64)txid_sqn;

Later, in b.c, I have to reassemble tx_id into "slt" and "sqn".
=================================================
struct redo_xid {
u_int sqn;
u_short slot;
};

Can I use the following expression to achieve this goal?
==================================================
struct redo_xid xid = (struct redo_xid)tx_id;

Many many thanks!
 
N

Nick Keighley

I am not good at bitwise operation,

they aren't that complicated...

so I wonder if some experts could
do me a help.

In a.c, somebody defined
================================================
# define u_int64 unsigned long long

long long doesn't have to be 64-bits

# define u_short unsigned short
# define u_int unsigned int

you appear to be assuming int is 32 bits. It doesn't have to be.
I generally don't like typedefs like this.

u_short txid_slt;
u_int txid_sqn;

u_int64 tx_id= ((u_int64)txid_slt << 32) | (u_int64)txid_sqn;

I wouldn't bother with the casts.

u_int64 tx_id = (txid_slt << 32) | txid_sqn;

Later, in b.c, I have to reassemble tx_id into "slt" and "sqn".
=================================================
struct redo_xid {
u_int sqn;
u_short slot;

};

Can I use the following expression to achieve this goal?
==================================================
struct redo_xid xid = (struct redo_xid)tx_id;

why not reverse the previous step?

struct redo_xid xid;

xid.sqn = tx_id & 0xffffffff; /* 32 1s */
xid.slot = (tx_id >> 32) & 0xffff;


--
Nick Keighley

Casting is almost always wrong,
and the places where it's right are rarely the places you'd guess.
Richard Heathfield
 
M

Martin Wells

loudking:
# define u_int64 unsigned long long
# define u_short unsigned short
# define u_int unsigned int


C has typedef for a reason:

typedef long long unsigned u_int64;
typedef short unsigned u_short;
typedef unsigned u_int;

The syntax for typedef is the same for defining a variable:

int (*x)[7]; /* x is a variable */
typedef int (*x)[7]; /* x is a type */


You'll notice the difference when you try:

typedef int *Type1;
#define Type2 int*

int main(void)
{
const Type1 a;
const Type2 b;

b = 0;

return 0;
}


u_short txid_slt;
u_int txid_sqn;

u_int64 tx_id= ((u_int64)txid_slt << 32) | (u_int64)txid_sqn;

Later, in b.c, I have to reassemble tx_id into "slt" and "sqn".
=================================================
struct redo_xid {
u_int sqn;
u_short slot;

};

Can I use the following expression to achieve this goal?
==================================================
struct redo_xid xid = (struct redo_xid)tx_id;


None of the C Standards say that you can... in fact they explicitly
allow an implementation to explode in your face if you try. As for
*your own* platform... who knows...

Martin
 
J

James Kuyper

Nick said:
they aren't that complicated...



long long doesn't have to be 64-bits



you appear to be assuming int is 32 bits. It doesn't have to be.
I generally don't like typedefs like this.

Actually, the code below does imply that assumption, it could also be
the case that u_int is either larger or smaller than 32 bits, but that
every value that actually needs to be stored in a 'u_int' type fits in
32 bits, or an unsigned int, whichever is smaller. That makes this code
non-portable, but making it portable would require knowing exactly what
the valid range of the following two variables is, which we don't know:
I wouldn't bother with the casts.
>
> u_int64 tx_id = (txid_slt << 32) | txid_sqn;

Without the first cast, txid_slt would be promoted to 'int', unless
USHRT_MAX > INT_MAX, in which case it would be promoted to 'unsigned int'.

If it gets promoted to 'int', then the left shift has undefined behavior
unless

INT_MAX >= (u_int64)USHRT_MAX << 32

If it gets converted to 'unsigned int', the left shift will have defined
behavior, but that defined behavior involves multiplying by 2^32, and
then reducing the result modulo UINT_MAX+1, which will discard
high-order bits unless

UINT_MAX >= (u_int64)USHRT_MAX << 32

See 6.5.7p4 for details.

However, I agree that the second cast is unnecessary - it will happen
automatically as a side effect of the first cast.

No - there is no such conversion.
why not reverse the previous step?

struct redo_xid xid;

xid.sqn = tx_id & 0xffffffff; /* 32 1s */
xid.slot = (tx_id >> 32) & 0xffff;

The mask in is unnecessary for the calculation of xid.slot. It may
actually discard data if unsigned_short is larger than 32 bits (which is
unlikely, especially for this code, but it would be possible).
 
K

Keith Thompson

Martin Wells said:
loudking:

C has typedef for a reason:

typedef long long unsigned u_int64;
typedef short unsigned u_short;
typedef unsigned u_int;
[...]

Agreed. C also has "unsigned short" and "unsigned int" for a reason.
Just refer to "unsigned short" and "unsigned int" directly. The
aliases "u_short" and "u_int" add nothing useful; they just make me
wonder why you bothered to define new names for types that already
have perfectly good names -- or, worse, whether you've defined
"u_short" as something other than "unsigned short".

As for u_int64, unsigned long long is required to be *at least* 64
bits, but it's allowed to be wider.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top