我曾经认为每个内存位置包含8位,16位,32位或64位。因此0101将作为00000101存储在8位机器中(如果是负数则符号扩展)。这是好的和花花公子,直到我出于好奇心在java中编写一个程序,以找出这个系统的更多内部工作。
有问题的方法如下:
public void printBinaryRep(File f){
try{
FileInputStream inputStream = new FileInputStream(f);
int next = 0;
byte b = 0;
while((next = inputStream.read()) != -1){
b = (byte)next;
System.out.println((char)next + " : "+Integer.toBinaryString(next));
}
inputStream.close();
}
catch(Exception e){System.out.println(e);}
}
我从一个名为Hello World
的文件中获得了此输出H : 1001000
e : 1100101
l : 1101100
l : 1101100
o : 1101111
: 100000
W : 1010111
o : 1101111
r : 1110010
l : 1101100
d : 1100100
除了空间外,所有这些都很好看。它有6位而不是8位。 我现在想知道所有这些信息是如何存储在内存中的。如果所有这些都存储在8位块中,比如
你好:10010001100101110110011011001101111
然后你可以简单地查看每个8位块并找出它所代表的数字(然后是它所指的ASCII码)。 当一个不同大小的字符(如6位空格和4位/ n)与它们一起存储时,它是如何工作的?那么不会在大的位空间中存储少量的数据会浪费很多比特吗?
我认为我的一些基本理解是错误的(或者某个地方的程序错了......)。对不起,如果这个问题听起来很奇怪或太不必要。我只是想知道。我做了一些谷歌搜索,但它没有提出任何相关的东西。如果你能让我知道我哪里出错了或者指出了我正确的方向,我会非常感激。 谢谢!
答案 0 :(得分:8)
你最好在C和/或汇编中试验,而不是Java。这些语言是较低级别的,并直接暴露地址空间。
我以前认为每个记忆 location包含8,16,32或64 位。因此0101将存储在8中 位机为00000101(符号扩展 如果它是负面的)。这一切都很好 和花花公子,直到我写了一个程序 java出于好奇而找出一些 这个系统的更多内部运作。
x86系统中的所有内存位置都包含8位(1个字节)。如果某个值包含的数据超过单个字节的数据,则使用多个字节进行存储。例如,在C中,“float”类型使用4个字节(32位)存储。
所有这些看起来都很好,除了 空间。它有6位而不是8位。我是 现在想知道这一切是怎么回事 信息存储在内存中。如果 所有这些都存储在8位块中, 像
空间也存储在一个字节中。您的打印代码忘记填充8个空格。 100000 == 00100000 == 0x20。
答案 1 :(得分:7)
空间也有8位。只是Integer.toBinaryString不会像你使用它那样打印前导0
位。
对于所有前导0
位,它实际上在内存中看起来像这样:
H : 01001000
e : 01100101
l : 01101100
l : 01101100
o : 01101111
: 00100000
W : 01010111
o : 01101111
r : 01110010
l : 01101100
d : 01100100
答案 2 :(得分:4)
您的原始直觉(大多数)是正确的:所有内存位置都包含相同的位数。在所有现代机器上,“byte”中有8位,其中一个字节是机器可以单独访问的最小内存块。
仔细观察你的输出。除空格外,所有数字都有七个数字。空间恰好以二进制表示中的两个零开头,而其他字母以一个开头。
答案 3 :(得分:3)
实际上你的做法是错误的。编码在这里非常重要。
如果您使用ASCII,那么您可以很容易地说每个字符都存储在一个字节(8位)中,但是当编码更改时,您不能这么说。
例如:UTF-8对字符串上的每个字符使用一到三个字节(8到24位)。这就是为什么你会看到一个重载,你可以在其中指定inputstream对象的编码。
选择错误的输入流绝对会导致错误的字符串输出。因此,您必须知道文件的编码,以了解哪个位意味着什么。实际上fileinputstream会为你做这件事。
如果将数字存储为字符串,则在硬盘驱动器中将使用字符长度。就像另一个角色一样。
但是,如果将123456789存储为ASCII编码的字符串,则需要9 * 8位= 72位。
如果将其存储为整数,(请注意,不同环境中整数的数据宽度不同),它只需要16位。
你也不能确定
H : 01001000
e : 01100101
l : 01101100
l : 01101100
o : 01101111
: 00100000
W : 01010111
o : 01101111
r : 01110010
l : 01101100
d : 01100100
\n: 00001010
以H:01001000存储在硬盘中 e:01100101 l:01101100 l:01101100 o:01101111 :00100000 W:01010111 o:01101111 r:01110010 l:01101100 d:01100100 \ n:00001010
你无法确定。文件系统并不那么简单。也许Hello是连续的,但是World string是在驱动器的末尾。这就是为什么有碎片整理命令。
但是如果我们在定义字符串时讨论主存储器(RAM),我希望位是连续的。至少在C中它是。你可以定义一个这样的字符串。
char[100] value; // c is a char array. (there is no string type in c)
这里value [0]是我们字符串的第一个字符。并且value仅解析内存中char数组的位置。
如果value [0]的地址是10,则值[1]的地址是10 + 8 = 18。
答案 4 :(得分:3)
计算机存储数字的方式可以与汽车里程表进行比较。如果里程表有4位数字,它将数字33存储为“0033”。
如果某人问你你的里程数是多少,你就不会说“零零三十三”。默认情况下,Java也没有。 (虽然你可以告诉它。)
那么不会在大的位空间中存储少量数据会浪费很多位吗?
嗯,不是真的。假设你的内存中有11000100。计算机应该如何知道这意味着11000100,或11000后跟100,还是1后跟1000后跟100,依此类推?
嗯,实际上计算机只是遵循它给出的程序(请记住,Java程序部分是由您创建的,部分是由设计Java的人创建的)。如果你可以创建一个可行的系统来保存位,你可以让计算机去做。
但是,请记住,在处理器使用和编程难度方面存在折衷。由于典型的计算机可以比使用7位或可变位数更快地使用字节多,因此以字节存储ASCII代码是存储文本的一种非常常见的选择。
但是让我回到你的问题。
那么不会在大的位空间中存储少量数据会浪费很多位吗?
数学上说,没有。一个名为Information Theory的数学分支告诉我们,绝对必要的位数取决于你想要编码的可能性以及它们各自的可能性。
假设您只有四个字母的字母(A,B,C,D),并使用两位数字(分别为00,01,10,11)来表示它。如果这些字母中的每一个都具有相同的可能性,则每个字母所需的最小位数(平均值)为2.换句话说,即使A为00且B为01,也存在 no 浪费的位
另一方面,如果您使用ASCII并将A,B,C,D编码为以下7位数字:
A: 1000001
B: 1000010
C: 1000011
D: 1000100
然后你每个字母“浪费”5位(即使你不是“在一个大的位空间存储小数字”)。
在设计压缩算法时,这些考虑因素很重要,对于日常应用程序而言并不那么重要。如果你想学习C,理解位和字节当然很重要。
答案 5 :(得分:2)
根据Java 4 API,
如果参数为负,则无符号整数值为参数加232;除此以外 它等于论证。该值将转换为二进制的ASCII数字字符串 (基数2)没有额外的前导0。
实际上,数据存储实际上要复杂得多。为了提高处理效率,大多数数据类型都存储在字边界,这意味着32位机器上的4个字节,或64位机器上的8个字节。数组可能包含得更紧密,因此char [4]
最终可能会使用与char
相同数量的“实际空间”。
Java是一个虚拟机,我不确定它使用的内存架构(如果有的话)。
答案 6 :(得分:1)
清除它。我的主要问题是我在开始时忽略了零。当我正在阅读有关压缩算法的更多内容时,我正在尝试这个(即gzip) 我假设所有这些都是ASCII。看到表示不是程序的目标,但是每个单词的不同位数使我偏离了为我正在处理的文件类型实现基本的,基于索引的压缩的最初目标。一旦我在Java中有一个概念证明,我会尝试在C中重写它。
谢谢!
答案 7 :(得分:0)
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Integer.html#toBinaryString%28int%29
Integer.ToBinarys的规范如下:
“此值转换为二进制(基数2)中的ASCII数字字符串 没有额外的领先0“
你忽略了这个事实是导致你混淆的原因。