thanks very much for clarifying! yes, you are more
or less right. but i do need all the variants:
- encoded little endian (goes into bytestream)
- encoded big endian (goes into bytestream)
- only low byte (for other reasons)
- only high byte (for other reasons)
Now there's one thing you have to be aware of with bytes, or else
you'll mix things up: An 8-bit byte is basically just one
"character." Bytes have numerical "values," however, which are often
expressed in hexadecimal or decimal representation. What's important
to know is that these numerical "values" may represent the byte (or
"character"), but they are NOT the same.
Let me clarify with an example. Let's say you had a byte, like
this:
my $byte = 'A';
The $byte itself equals the character 'A', so this would be true:
if ($byte eq 'A') # evaluates to true (note the use of "eq")
and this would print out 'A':
print $byte; # prints out 'A'
but its "value" is actually 65 (or 0x41 in hexadecimal
representation). You can see this with the following code:
my $byteValue = ord($byte);
print $byteValue; # prints out "65"
As you might already know, the ord() function takes a single byte
and returns its numeric value. (The opposite of ord() is chr(), and
you can read about both in "perldoc -f ord" and "perldoc -f chr".)
So I have a question for you: When you say you need the high/low
byte, does that mean you need the literal byte "character," or the
byte's numerical "value"?
If you only need the numerical byte values, this is easy to do, as
it just involves doing mathematical operations on the $integerToSend,
like this:
my $integerToSend = 2008;
my $lowByteValue = integerToSend % 256; # 216
my $nextByteValue = (integerToSend >> 8) % 256; # 7
But if instead of the numerical byte value, you need the literal
byte character, you would just extract out the characters from the
$stringToSend, like this:
my $integerToSend = 2008;
my $stringToSend = pack('v', $integerToSend); # note little-
endian
my $lowByte = substr($stringToSend, 0, 1);
my $nextByte = substr($stringToSend, 1, 1);
(To learn more about the substr() function, read "perldoc -f substr".)
Note that if you print() out the $lowByte and $nextByte variables
you won't necessarily see numbers; what you'll see are characters that
correspond to values 7 and 216.
Also note that I've avoided using the term $highByte (even though I
used the term $lowByte). The reason for this is because if you try to
pack() a large value (like 200,000) into a two-byte string, the high-
bytes will be lost (meaning that the byte next to the low byte isn't
really the high byte, since the high byte(s) weren't recorded). To
avoid the confusion, I use $nextByte instead.
but what happens if for unexpected reasons:
$integerToSend = 200000;
my $stringToSend = pack('n', $integerToSend);
is it correct, that this is truncated to 65025?
I'm curious: Why do you say "65025"? Is it because you mean the
largest unsigned two-byte (16-bit) integer? If so, that's actually
256^2-1, which is actually 65535.
At any rate, no, it doesn't truncate it to either 65025 nor 65535.
What it does is convert the value 200000 to bytes whose values are 0,
3, 13, and 64, but since it can only keep two of them, it discards the
first two bytes and only keeps the lower two bytes (the ones whose
values are 13 and 64). And so 13*256 + 64 equals 3392.
So if you modified the code you gave a little while ago to this
code and ran it:
my $integerToSend = 200000;
my $stringToSend = '';
print "\n4 byte-values (big-endian):\n";
$stringToSend = pack('N', $integerToSend);
print ord, "\n" foreach split //, $stringToSend;
print "\n2 byte-values (also big-endian):\n";
$stringToSend = pack('n', $integerToSend);
print ord, "\n" foreach split //, $stringToSend;
you would see this output:
4 byte-values (big-endian):
0
3
13
64
2 byte-values (also big-endian):
13
64
(Note that the first two values are discarded when displaying only two
byte-values.)
problem 2: only high and low bytes (similar story)
what is the best (fastest, safest) way to extract
the lowest two bytes of an decimal of unknown length?
i'm currently using
my $integerToSend = 2008;
my $lowbyte = $decimal % 256;
my $highbyte = $decimal >> 8;
but i doubt that this is the 'proper' way to do it.
especially when (again) for uexpected reasons:
my $integerToSend = 200000;
my $lowbyte = $decimal % 256;
my $highbyte = $decimal >> 8;
If you're looking for byte "values," you can use what I did above:
my $integerToSend = 20000;
my $lowByteValue = integerToSend % 256; # 32
my $nextByteValue = (integerToSend >> 8) % 256; # 78
If you're looking for the literal byte "characters," you can
convert the values to byte-characters with the chr() function, like
this:
my $lowByte = chr($lowByteValue);
my $nextByte = chr($nextByteValue);
or you can pack() the $integerToSend to a $stringToSend with little-
endian ordering, and just extract out the first and second characters,
like this:
my $stringToSend = pack('v', $integerToSend); # note: little-
endian
my $lowByte = substr($stringToSend, 0, 1); # gets first byte
my $nextByte = substr($stringToSend, 1, 1); # gets next byte
thanks for your comments. you've almost put me back
on track...
You're very welcome.
Don't forget the distinction between the byte values and the bytes
themselves. Otherwise, if you want to send the bytes for the number
2008 over a bytestream, but send the strings "7" and "216" over
instead, you'll be sending the string "7216" (a four-byte string)
instead of $stringToSend (a two-byte string).
I hope this helps, Susanne.
-- Jean-Luc