GoldenNewby
GoldenNewby

Reputation: 4452

Convert bit vector to binary in Perl

I'm not sure of the best way to describe this.

Essentially I am attempting to write to a buffer which requires a certain protocol. The first two bytes I would like to are "10000001" and "11111110" (bit by bit). How can I write these two bytes to a file handle in Perl?

Upvotes: 2

Views: 968

Answers (3)

Greg Bacon
Greg Bacon

Reputation: 139491

Since version 5.6.0 (released in March 2000), perl has supported binary literals as documented in perldata:

Numeric literals are specified in any of the following floating point or integer formats:

12345
12345.67
.23E-10        # a very small number
3.14_15_92     # a very important number
4_294_967_296  # underscore for legibility
0xff           # hex
0xdead_beef    # more hex
0377           # octal (only numbers, begins with 0)
0b011011       # binary

You are allowed to use underscores (underbars) in numeric literals between digits for legibility. You could, for example, group binary digits by threes (as for a Unix-style mode argument such as 0b110_100_100) or by fours (to represent nibbles, as in 0b1010_0110) or in other groups.

You may be tempted to write

print $fh 0b10000001, 0b11111110;

but the output would be

129254

because 10000001₂ = 129₁₀ and 11111110₂ = 254₁₀.

You want a specific representation of the literals’ values, namely as two unsigned bytes. For that, use pack with a template of "C2", i.e., octet times two. Adding underscores for readability and wrapping it in a convenient subroutine gives

sub write_marker {
  my($fh) = @_;
  print $fh pack "C2", 0b1000_0001, 0b1111_1110;
}

As a quick demo, consider

binmode STDOUT or die "$0: binmode: $!\n";  # we'll send binary data
write_marker *STDOUT;

When run as

$ ./marker-demo | od -t x1

the output is

0000000 81 fe
0000002

In case it’s unfamiliar, the od utility is used here for presentational purposes because the output contains a control character and Þ (Latin small thorn) in my system’s encoding.

The invocation above commands od to render in hexadecimal each byte from its input, which is the output of marker-demo. Note that 10000001₂ = 81₁₆ and 11111110₂ = FE₁₆. The numbers in the left-hand column are offsets: the special marker bytes start at offset zero (that is, immediately), and there are exactly two of them.

Upvotes: 1

cjm
cjm

Reputation: 62109

To convert spelled-out binary to actual bytes, you want the pack function with either B or b (depending on the order you have the bits in):

print FILE pack('B*', '1000000111111110');

However, if the bytes are constant, it's probably better to convert them to hex values and use the \x escape with a string literal:

print FILE "\x81\xFE";

Upvotes: 4

Joni
Joni

Reputation: 111259

How about

# open my $fh, ...
print $fh "\x81\xFE"; # 10000001 and 11111110

Upvotes: 1

Related Questions