rsmets
rsmets

Reputation: 919

How does an "int" represent a byte (8 bits) when an int is normally 32 or 64 bits?

I'm curious how in the Dart programming language a byte is represented by the int type. I am confused because in Java, which Dart closely resembles, an int is 32 bits.

I ask because the leading flutter ble library, Flutter Blue, seems to handle List<int> while handling the ble bytes.

However according to the official documentation: https://flutter.dev/docs/development/platform-integration/platform-channels#codec Uint8List is used - which is what makes sense as the byte[] equivalent.

It seems the unsigned 8 bit integers are just then converted to a 32 bit signed int going from Uint8List -> List<int> ? i.e. decimal 2 is then converted from 00000010 to 00000000000000000000000000000010?

It seems this has ramifications if one would like to write a byte stream. Would one need to cast the int's to Uint8's?

Upvotes: 2

Views: 5779

Answers (5)

lrn
lrn

Reputation: 71828

The Dart int type is a 64-bit two's complement number—except when compiled for the web, there it's a 64-bit floating point number with no fractional part (a JavaScript number which has an integer value).

How those values are represented internally depends on optimizations, they can be represented as something smaller if the runtime system knows for sure that the value will fit. That's an optimization, you won't be able to tell the difference.

A "byte" value is an integer in the range 0..255. You can obviously store a byte value in an int.

The most efficient way to store multiple bytes is a Uint8List, which implements List<int>. It stores each element as a single octet. When you read a value out of a Unit8List, its byte value is represented by an int. When you store an int in the Uint8List, only the low 8 bites are stored. So it does expanding reads and truncating writes to move values between an octet and a 64-bit value.

Upvotes: 3

smac89
smac89

Reputation: 43206

There shouldn't be any confusion as to how an int can be used to represent bytes because it all comes down to bits and how you store and manipulate them.

For the sake of simplicity, let us assume that an int is larger than a byte - an int is 32 bits, and a byte is 8 bits. Since, we are dealing with just bits at this point, you can see it is possible for an int to contain 4 bytes because 32/8 is 4 i.e. we can use an int to store bytes without loosing information.

It seems as those the unsigned 8 bit integers are just then converted to a 32 bit signed int going from Uint8List -> List ? i.e. decimal 2 is is then converted from 00000010 to 00000000000000000000000000000010?

You could do it that way, but from I said previously, you can store multiple bytes in an int.

Consider if you have the string Hello, World!, which comes up to 13 bytes and you want to store these bytes in a list of ints, given each int is 32 bits; We only need to use 4 ints to represent this string because 13 * 8 is 104 bits, and four 32bit ints can hold 128 bits of information.

It seems this has ramifications if one would like to write a byte stream. Would need to cast the int's to Uint8's.

Not necessarily.

A byte stream consisting of the bytes 'H', 'e', 'l', 'l', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!' can be written into a data structure known as a Bit Array. The bit array for the above stream would look like:

[01001000011001010110110001101100011011110010110000100000010101110110111101110010011011000110010000100001]

Or a list of 32 bit ints:

[1214606444,1865162839,1869769828,33]

If we wanted to convert this list of ints back to bytes, we just need to read the data in chunks of 8 bits to retrieve the original bytes. I will demonstrate it with this simply written dart program:

String readInts(List<int> bitArray) {
  final buffer = StringBuffer();
  for (var chunk in bitArray) {
    for (var offset = 24; offset >= 0; offset -= 8) {
      if (chunk < 1 << offset) {
        continue;
      }
      buffer.writeCharCode((chunk >> offset) & 0xff);
    }
  }
  return buffer.toString();
}

void main() {
  print(readInts([1214606444,1865162839,1869769828,33]));
}

The same process can be followed to convert the bytes to integers - you just combine every 4 bytes to form a 32 bit integer.

Output

Hello, World!

Of course, you should not need to write such a code by yourself because dart already does this for you in the Uint8List class

Upvotes: 2

jamesdlin
jamesdlin

Reputation: 90155

Uint8List derives from List<int>; passing a Uint8List where a List<int> is expected does not change the representation of the data.

When you read a single int from a Uint8List (e.g. with operator []), you'll get a copy of the octet widened to whatever int is.

When you write an int to a Uint8List (e.g. with operator []=), the stored value will be truncated to include only the lower 8-bits.

Upvotes: 1

Abion47
Abion47

Reputation: 24746

First, let's clear up one thing. An int is not inherently 32-bits or 64-bits universally. That's just a convention put in place by common languages, including Java. In C, for example, the size of int is an implementation detail that depends on the compiler, the architecture, and the size of a memory address, so it could be 8, 16, 32, or 64 bits (or on more esoteric platforms, something else entirely, like 24 bits). So the notion that Dart is doing something "wrong" by not having int be a 32-bit integer type is somewhat absurd.

Now that that, is out of the way, an int in Dart is not a fixed data type. Like C, it depends on the platform that it is running on.

  • Mobile: int is a 64-bit integer
  • Web: int is mapped to the JavaScript Number which is a 64-bit floating point (i.e. double)
  • Other: int can be defined as an implementation detail

And that's it. Dart has no concept of any other integral type. (i.e. There's no such thing as a byte, short, char, long, long long, etc. as primitive types.)

What you are seeing in Uint8List is an abstraction over a list of 64-bit integers to make it appear like a list of bytes. I'm not sure how it is represented internally (either each "byte" is its own int, using bit-flags to store 8 bytes worth of information in a single int, or it's a native implementation doing something else entirely), but at the end of the day it doesn't really matter.

Upvotes: 1

Christopher Moore
Christopher Moore

Reputation: 17141

The size of an int in dart is not completely predictable for local variables as Irn mentions here. The size of the int may be reduced as an optimization if it is seen as possible.

If you do an explicit conversion from Uint8List to List<int> that creates a new List object, the new object will have int elements that are a larger size than 8 bits. Possibly 32 bits, maybe 64 bits, maybe less. The compiler will choose based on what it sees. According to the int class, the default is a signed 64 bit integer.

If you are trying to get from ints to a Uint8List, each int will be truncated to 8 bits.

Upvotes: 1

Related Questions