bits of this, bits of that

B

Ben

Hi,

I need to write some data types into an array of unsigned chars.

These are basically "signals" within a message, so each signal will have
a start bit and a length. The signals will also have a type, one of:
unsigned long
signed long
float
double

The signals with float and double will be 32 or 64 bits long, as
appropriate.

I need to just shift the bits and throw them into the array, untouched.
Whats the best way of doing this?

Since I can't bit shift a float around, I was thinking of a union of the
4 types, and doing all the bit twiddling using the unsigned type. Is
this going to work, or am I asking for trouble? Presumably there's a
better way.

Cheers for any insights,

Ben
 
S

Srini

Hi,
I need to write some data types into an array of unsigned chars.

These are basically "signals" within a message, so each signal will have
a start bit and a length. The signals will also have a type, one of:
unsigned long
signed long
float
double

The signals with float and double will be 32 or 64 bits long, as
appropriate.

I need to just shift the bits and throw them into the array, untouched.
Whats the best way of doing this?

Since I can't bit shift a float around, I was thinking of a union of the
4 types, and doing all the bit twiddling using the unsigned type. Is
this going to work, or am I asking for trouble? Presumably there's a
better way.

Cheers for any insights,

Ben

I'm not sure I completely understand what you're trying to accomplish.
But looks like std::bitset can help you out here. Its a bit-vector and
provides constant time access to the bits. You can also shift around
bits and use bitwise operators on it.

Srini
 
B

Ben

Srini said:
I'm not sure I completely understand what you're trying to accomplish.

OK, I'm trying to pack signals into a data frame to be sent over a
communications channel. Those signals can have 4 distinct types, which
are known a priori for each frame. The signals have a length (which may
be restricted by it's type), and a start bit within the frame.

So, a Signal of type float, would have 32 bits, and could start at say,
the 5 bit within a 64bit data frame.
But looks like std::bitset can help you out here. Its a bit-vector and
provides constant time access to the bits. You can also shift around
bits and use bitwise operators on it.

Thats interesting, but what is the recommended way of getting the bits
in my float into and out of the bitset?

Ben
 
C

Chris Theis

Ben said:
Hi,

I need to write some data types into an array of unsigned chars.

These are basically "signals" within a message, so each signal will have a
start bit and a length. The signals will also have a type, one of:
unsigned long
signed long
float
double

The signals with float and double will be 32 or 64 bits long, as
appropriate.

I need to just shift the bits and throw them into the array, untouched.
Whats the best way of doing this?

Since I can't bit shift a float around, I was thinking of a union of the 4
types, and doing all the bit twiddling using the unsigned type. Is this
going to work, or am I asking for trouble? Presumably there's a better
way.

Cheers for any insights,

Why do you need different data types for the signals? I'd recommend to take
a look at vector<bool> or at the bitset classes for your application.

Cheers
Chris
 
S

Srini

OK, I'm trying to pack signals into a data frame to be sent over a
communications channel. Those signals can have 4 distinct types, which
are known a priori for each frame. The signals have a length (which may
be restricted by it's type), and a start bit within the frame.

So, a Signal of type float, would have 32 bits, and could start at say,
the 5 bit within a 64bit data frame.

I don't think using floating point types and using them to pack data
into a frame is a good idea. If its just a particular number of bits
you want to use to pack into a frame, you can use std::bitset.

Ex: If you want 50 bits,

std::bitset<50> bits_50;

You can get the unsigned long value of any bitset.

And I still don't understand what you mean by "type of a signal". If
you want to capture the type of a signal in the frame you're sending so
that the other side can know what type of signal is in the frame, then
why not designate 2 bits in the frame to indicate the type of signal.

00 - unsigned long
01 - signed long
10 - float
11 - double

Would this meet your requirement or am I still wrong in understnading
your problem?
Thats interesting, but what is the recommended way of getting the bits
in my float into and out of the bitset?

I do not know of any portable way of doing this. If you want to pack
the bits from a float variable into the frame, you could do a (an ugly)
reinterpret_cast.

Srini
 
M

msalters

Ben schreef:
OK, I'm trying to pack signals into a data frame to be sent over a
communications channel. Those signals can have 4 distinct types, which
are known a priori for each frame. The signals have a length (which may
be restricted by it's type), and a start bit within the frame.

Do you know the formats of the wire types? Are they identical to the
C++ types? After all, ISO C++ does not prescribe how the bits in a type
are used. In fact, for any type but char, there are at least 2 common
implementations (for char, the common implementation is 8 bits, but
even
this is not universal)
So, a Signal of type float, would have 32 bits, and could start at say,
the 5 bit within a 64bit data frame.

However, your C++ float may be 64 bits. Trouble...
Thats interesting, but what is the recommended way of getting the bits
in my float into and out of the bitset?

The best way would be to find out what your wire protocol is (probably
1 sign bit, M mantissa bits and E exponent bits), calclulate the two
unsigned longs MBits and Ebits, with MBits < (1<<M) and EBits < (1<<E)
then add the sign bit, the lower M bits from MBits and the lower E bits
from EBits. If the base is 2, EBits is simple, calculate the 2-log. You
can then divide by 1<<EBits (or multiply by 1<<-EBits) to get MBits.
(base-16 is only a bit more tricky)

The advantage is that the algortihm works on the value of your float,
not the representation of this value in memory.

HTH,
Michiel Salters
 
B

Ben

msalters said:
Ben schreef:

That confused me for a moment, I wondered Ben schreef was!
Do you know the formats of the wire types? Are they identical to the
C++ types? After all, ISO C++ does not prescribe how the bits in a type
are used. In fact, for any type but char, there are at least 2 common
implementations (for char, the common implementation is 8 bits, but
even
this is not universal)

Yep, that problem I know about. There is only one platform / compiler
and it's correct.
However, your C++ float may be 64 bits. Trouble...

As above.
The best way would be to find out what your wire protocol is (probably
1 sign bit, M mantissa bits and E exponent bits), calclulate the two
unsigned longs MBits and Ebits, with MBits < (1<<M) and EBits < (1<<E)
then add the sign bit, the lower M bits from MBits and the lower E bits
from EBits. If the base is 2, EBits is simple, calculate the 2-log. You
can then divide by 1<<EBits (or multiply by 1<<-EBits) to get MBits.
(base-16 is only a bit more tricky)

The advantage is that the algortihm works on the value of your float,
not the representation of this value in memory.

Yeah, understood. I might just have to go this route.

Ben
 
B

Ben

Srini said:
I don't think using floating point types and using them to pack data
into a frame is a good idea.

I need to pack the floating point number into the frame, whether it's a
good thing to do or not is not up to me, I'm just providing the
functionality for my users. The data is specified as the format my
compiler uses, so I literally just need to transfer the bits in and out.
> If its just a particular number of bits
you want to use to pack into a frame, you can use std::bitset.

Ex: If you want 50 bits,

std::bitset<50> bits_50;

You can get the unsigned long value of any bitset.
OK.

And I still don't understand what you mean by "type of a signal". If
you want to capture the type of a signal in the frame you're sending so
that the other side can know what type of signal is in the frame, then
why not designate 2 bits in the frame to indicate the type of signal.

00 - unsigned long
01 - signed long
10 - float
11 - double

Would this meet your requirement or am I still wrong in understnading
your problem?

The signal types are known a priori, so there is no requirement to
specify the type, length etc within the frame. I just need the 32 bits
of a float or 64 bits of a double to be in the frame, offset by the
required startbit.
I do not know of any portable way of doing this. If you want to pack
the bits from a float variable into the frame, you could do a (an ugly)
reinterpret_cast.

Hmm, can't seem to make reinterpret_cast work:


#include <iostream>
#include <bitset>
#include <string>
#include <sstream>
#include <stdexcept>

class Frame {
public:
static const LENGTH = 64;
typedef std::bitset<LENGTH> Data;
Frame() : data_(0) {}
void SetSignal(size_t startBit, size_t length, unsigned long value) {
if (64 < startBit + length) {
throw std::range_error("Signal too long");
} else {
Data mask = ~(0xffffffff<<(length));
Data temp(value & mask.to_ulong());
data_ &= ~(mask<<(LENGTH-startBit-length));
data_ |= temp<<(LENGTH-startBit-length);
}
}
unsigned long GetSignal(size_t startBit, size_t length) {
if (64 < startBit + length) {
throw std::range_error("Signal too long");
} else {
Data mask = ~(0xffffffff<<(length));
Data temp = data_>>(LENGTH-startBit-length);
temp &= mask;
return temp.to_ulong();
}
}

std::string ToString() {
std::stringstream ss;
for (int i = LENGTH-1; i>=0; --i) {
if (7 == i%8) {
ss << std::endl << 7-i/8 << ": ";
} else if (3 == i%4) {
ss << " ";
}
ss << data_;
}
return ss.str();
}
private:
Data data_;
};

int main(int argc, char* argv[])
{
Frame frame;

std::cout << frame.ToString() << std::endl << std::hex;

int intVal = 0x55;
frame.SetSignal(32, 8, intVal);
std::cout << frame.ToString() << std::endl;
std::cout << "0x" << frame.GetSignal(32, 8) << std::endl;

float floatVal = 47/5;
frame.SetSignal(0, 32, reinterpret_cast<unsigned long>(floatVal));
std::cout << frame.ToString() << std::endl;
std::cout << "0x" << reinterpret_cast<float>(frame.GetSignal(0, 32))
<< std::endl;

return 0;
}

What do you think? In VC7.1 I get:

test.cpp(61): error C2440: 'reinterpret_cast' : cannot convert from
'float' to 'unsigned long'
Conversion is a valid standard conversion, which can be
performed implicitly or by use of static_cast, C-style cast or
function-style cast


Ben
 
M

mlimber

Ben wrote:
[snip]
I do not know of any portable way of doing this. If you want to pack
the bits from a float variable into the frame, you could do a (an ugly)
reinterpret_cast.

Hmm, can't seem to make reinterpret_cast work: [snip]
float floatVal = 47/5;
frame.SetSignal(0, 32, reinterpret_cast<unsigned long>(floatVal));

If you want to use reinterpret_cast to do a bit-wise copy of a float
into a 32-bit int, you probably want something like this:

assert( sizeof(float) == sizeof(unsigned long) );
unsigned long uintVal = *reinterpret_cast<unsigned long*>( &floatVal
);

A compile-time assertion would be better than a run-time one, however.
See the Boost or Loki libraries for examples.

Cheers! --M
 
B

Ben Pope

mlimber said:
Ben wrote:
[snip]
Thats interesting, but what is the recommended way of getting the bits
in my float into and out of the bitset?

I do not know of any portable way of doing this. If you want to pack
the bits from a float variable into the frame, you could do a (an ugly)
reinterpret_cast.

Hmm, can't seem to make reinterpret_cast work:
[snip]

float floatVal = 47/5;
frame.SetSignal(0, 32, reinterpret_cast<unsigned long>(floatVal));


If you want to use reinterpret_cast to do a bit-wise copy of a float
into a 32-bit int, you probably want something like this:

assert( sizeof(float) == sizeof(unsigned long) );
unsigned long uintVal = *reinterpret_cast<unsigned long*>( &floatVal
);

A compile-time assertion would be better than a run-time one, however.
See the Boost or Loki libraries for examples.

OK, I get it, cheers.

I seem to have it working with a nasty union at the moment, but the cast makes sense now I see it.

Ben
 
B

Ben Pope

Chris said:
Why do you need different data types for the signals? I'd recommend to take
a look at vector<bool> or at the bitset classes for your application.

It's up to the user to decide what the signals will be, usually they are integers, but it's possible that they will require floating point arithmetic, too.

I'm implementing some functionality for compatibility with an existing API.

Ben
 
O

Old Wolf

Srini said:
Ex: If you want 50 bits,

std::bitset<50> bits_50;

You can get the unsigned long value of any bitset.

You can only get the unsigned long value of a bitset that
has 32 bits or fewer (or however many bits are in an
unsigned long on your system).
 
B

Ben Pope

Old said:
You can only get the unsigned long value of a bitset that
has 32 bits or fewer (or however many bits are in an
unsigned long on your system).

You can get the lower 32 bits into an unsigned long if the higher bits are not set, if they are it throws an error.

Ben
 
G

Greg

Ben said:
Hi,

I need to write some data types into an array of unsigned chars.

These are basically "signals" within a message, so each signal will have
a start bit and a length. The signals will also have a type, one of:
unsigned long
signed long
float
double

The signals with float and double will be 32 or 64 bits long, as
appropriate.

I need to just shift the bits and throw them into the array, untouched.
Whats the best way of doing this?

Since I can't bit shift a float around, I was thinking of a union of the
4 types, and doing all the bit twiddling using the unsigned type. Is
this going to work, or am I asking for trouble? Presumably there's a
better way.

Cheers for any insights,

Ben

Have you looked into BER (Basic Encoding Rules) and ASN.1 (Abstract
Syntax Notation)?

Free C source code and libraries for these two standards are available
on almost any platform (LDAP is implemented in BER). At the very least,
they would at least be instructive in showing how this kind of problem
has been solved before.

Greg
 
B

Ben

Greg said:
Have you looked into BER (Basic Encoding Rules) and ASN.1 (Abstract
Syntax Notation)?

Free C source code and libraries for these two standards are available
on almost any platform (LDAP is implemented in BER). At the very least,
they would at least be instructive in showing how this kind of problem
has been solved before.

Thats very interesting... I think those formalise what I'm talking about.

So if I were to write some ASN.1 for my signals, it would be possible to
have a set of libraries encode my data.

It would seem that I actually require a PER compiler, and that my data
has no preamble or length encoded within it, merely a value that is not
byte aligned.

Can anybody recommend any libraries that can do this?

Ben
 

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,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top