整数和字符之间的区别

时间:2015-12-09 05:49:52

标签: memory-management character-encoding

我刚刚开始学习c ++,并且在c ++中遇到过各种数据类型。我还了解了在指定数据类型时计算机如何存储值。在学习char数据类型时,我遇到的一个疑问是计算机如何区分整数和字符。

我了解到字符数据类型使用8位来存储字符,并且计算机可以通过遵循ASCII编码规则将字符存储在其存储位置中。但是,我没有意识到计算机如何知道字节00100001是否代表后者' a'或整数65.是否为此分配了特殊位?

5 个答案:

答案 0 :(得分:2)

当我们做的时候

int a = 65

char ch = 'a'

如果我们检查内存地址,我们会按预期看到值 00100001

在应用程序层中,我们选择强制转换为字符或整数

prinf("%d", ch)

将打印65

答案 1 :(得分:1)

字符在计算机内表示为整数。因此,数据类型“char”只是数据类型“int”的子集。

请参阅以下页面:将清除您心中的所有含糊之处。 Data Types Detail

答案 2 :(得分:1)

计算机本身不记得或设置任何位来区分字符和字符。相反,它是维护该信息并生成适当操作数据的适当机器代码的编译器。

你甚至可以覆盖和误导'编译器,如果你想。例如,您可以将char指针转换为void指针,然后转换为int指针,然后尝试读取称为int的位置。我认为'动态演员'也是可能的。如果使用了实际位,则无法执行此类操作。

添加更多详细信息以回应评论: 嗨,你应该问的是,谁将检索这些价值观?想象一下,您将内存的内容写入文件并通过Internet发送。如果接收者"知道"它的接收字符然后没有必要编码字符的身份。但是如果接收器可以接收字符或整数,则需要识别位。以同样的方式,当你编译一个程序并且编译器知道存储在哪里时,没有必要弄清楚'因为你已经知道了什么。现在如何将char编码为比特与浮点数与int进行编码由IEEE标准

等标准决定

答案 3 :(得分:1)

你问过一个简单而深刻的问题。 : - )

答案和一两个例子如下。 (请参阅底部的edit2,以获取更长的示例,该示例试图说明当您以不同方式解释单个内存位置的位模式时会发生什么)。

"深刻的"它的一个方面在于存在各种各样的字符编码。有很多 - 我打赌比你认为可能可能更多。 : - )

这是值得一读的:http://www.joelonsoftware.com/articles/Unicode.html 完整标题:"绝对最低每个软件开发人员绝对,必须知道Unicode和字符集(没有借口!)"

关于你的第一个问题:"计算机如何区分整数和字符": 计算机没有(无论好坏)。 位模式的含义可以通过读取它们来解释。

考虑这个示例位模式(8位或一个字节):

01000001b = 41x = 65d(分别为二进制,十六进制和十进制)。

如果该位模式基于ASCII,则表示大写A.

如果该位模式是EBCDIC,它将代表一个"非中断空间"角色(至少根据维基百科的EBCDIC图表,我看过的大多数其他人都没有说出在EBCDIC中65d的含义)。

(只是为了琐事,在EBCDIC中,' A'将完全用不同的位模式表示:C1x或193d。)

如果您读到该位模式是一个整数(可能是一个短整数),它可能表示您在银行账户(或欧元,或其他东西)中有65美元 - 就像您的位模式赢得的字符集一样#t; t有任何东西告诉你它是什么货币。

如果该位模式是显示器的24位像素编码的一部分(RBG为3个字节),则perhps' blue'在RBG编码中,它可能表示您的像素大约是25%蓝色(例如65/255大约是25.4%); 0%为黑色,100%为蓝色。

所以,是的,关于如何解释比特有很多变化。由您的程序来跟踪它。 编辑:通常添加元数据来跟踪,因此如果您正在处理货币,您可能有一个字节用于货币类型,其他字节用于给定货币的数量。货币类型也必须编码;有不同的方法可以做到这一点..." C ++ enum"试图以节省空间的方式解决:http://www.cprogramming.com/tutorial/enum.html)。

对于每个字符的8位(一个字节),这是您开始时的公平假设。但它并非总是如此。当你进入Unicode时,许多语言将为每个字符使用2个以上的字节。

然而...... ASCII很常见,它适合单个字节(8位)。 如果您正在处理简单的英文文本(A-Z,0-9等),那我就足够了。

花一些时间在这里浏览,看看acsii,ebcdic和其他人: http://www.lookuptables.com/

如果你在linux或smth上运行,hexdump可以成为你的朋友。 请尝试以下

$ hexdump -C myfile.dat 

无论您使用哪种操作系统,您都需要找到一个hexdump实用程序,您可以使用它来查看数据文件中的真正

你提到过C ++,我认为编写一个"这将是一个有趣的练习。 byte-dumper实用程序,只是一个简短的程序,它接受一个void *指针及其拥有的字节数,然后输出那么多字节值的值。

祝你学业顺利! : - )

编辑2:我添加了一个小型研究计划......我不知道如何更简洁地说明这个想法(在C语言中似乎比C ++更容易)。 总之...

在这个示例程序中,我有两个字符指针引用整数使用的内存。 实际的代码(参见'示例程序',下面的方法)对于转换更加混乱,但这说明了基本的想法:

unsigned short a;  // reserve 2 bytes of memory to store our 'unsigned short' integer.
char *c1 = &a;     // point to first byte at a's memory location.
char *c2 = c1 + 1; // point to next byte at a's memory location.

请注意' c1'和' c2'两者共享内存也被' a'。

使用

走过输出......
sizeof基本上告诉你一些东西使用了多少字节。

===== Message Here =====
行就像dump()函数打印出来的注释。

关于dump()函数的重要之处在于它正在使用内存位置中的位模式来实现' a'。 dump()不会更改这些位模式,它只是检索它们并通过cout显示它们。

在第一次运行中,在调用dump之前,我将以下位模式分配给:     a =(0x41 <&lt;&lt; 8)+ 0x42; 这左移0x41 8位并向其添加0x42。 结果位模式为= 0x4142(十进制16706,或100001 100010二进制)。 其中一个字节为0x41,另一个字节为0x42。 接下来它调用dump()方法:

dump( "In ASCII, 0x41 is 'A' and 0x42 is 'B'" );

注意在我的虚拟盒Ubuntu上运行的输出发现a的地址是0x6021b8。 它很好地匹配c1和amp;指向的预期地址。 C2。

然后我修改了&#39; a&#39; ...中的位模式     a + = 1;倾倒(); //为什么这会找到一个&#39; C&#39;而不是&#39; B&#39;?

a += 5;  dump(); // why did this find an 'H' instead of 'C' ?

当你深入研究C ++(也许是C)时,你会希望能够像这样(或多或少)绘制内存映射:

===开始记忆地图===

                   +-------+-------+
unsigned short   a : byte0 : byte1 :                  holds 2 bytes worth of bit patterns.
                   +-------+-------+-------+-------+
char *          c1 : byte0 : byte1 : byte3 : byte4 :  holds address of a
                   +-------+-------+-------+-------+
char *          c2 : byte0 : byte1 : byte3 : byte4 :  holds address of a + 1
                   +-------+-------+-------+-------+

=== end memory map ===

这是它运行时的样子;我鼓励您完成C ++代码 在一个窗口中,将每个输出连接回生成它的C ++表达式。

请注意我们有时会使用简单的数学来向a添加数字(例如&#34; a + = 1&#34;其次是&#34; a + = 5&#34;)。 请注意dump()从内存位置提取的字符的影响&#39; a&#39;。

===开始跑===

$ clear; g++ memfun.cpp
$ ./a.out
sizeof char =1, unsigned char =1
sizeof short=2, unsigned short=2
sizeof int  =4, unsigned int  =4
sizeof long =8, unsigned long =8
===== In ASCII, 0x41 is 'A' and 0x42 is 'B' =====
a=16706(dec), 0x4142 (address of a: 0x6021b8)
c1=0x6021b8 (should be the same as 'address of a')
c2=0x6021b9 (should be just 1 more than 'address of a')
c1=B
c2=A
in hex, c1=42
in hex, c2=41
===== after a+= 1 =====
a=16707(dec), 0x4143 (address of a: 0x6021b8)
c1=0x6021b8 (should be the same as 'address of a')
c2=0x6021b9 (should be just 1 more than 'address of a')
c1=C
c2=A
in hex, c1=43
in hex, c2=41
===== after a+= 5 =====
a=16712(dec), 0x4148 (address of a: 0x6021b8)
c1=0x6021b8 (should be the same as 'address of a')
c2=0x6021b9 (should be just 1 more than 'address of a')
c1=H
c2=A
in hex, c1=48
in hex, c2=41
===== In ASCII, 0x58 is 'X' and 0x42 is 'Y' =====
a=22617(dec), 0x5859 (address of a: 0x6021b8)
c1=0x6021b8 (should be the same as 'address of a')
c2=0x6021b9 (should be just 1 more than 'address of a')
c1=Y
c2=X
in hex, c1=59
in hex, c2=58
===== In ASCII, 0x59 is 'Y' and 0x5A is 'Z' =====
a=22874(dec), 0x595a (address of a: 0x6021b8)
c1=0x6021b8 (should be the same as 'address of a')
c2=0x6021b9 (should be just 1 more than 'address of a')
c1=Z
c2=Y
in hex, c1=5a
in hex, c2=59
Done.
$ 

=== end run ===

===开始示例程序===

#include <iostream>
#include <string>
using namespace std;

// define some global variables
unsigned short a; // declare 2 bytes in memory, as per sizeof()s below.
char *c1 = (char *)&a; // point c1 to start of memory belonging to a (1st byte).
char * c2 = c1 + 1; // point c2 to next piece of memory belonging to a (2nd byte).

void dump(const char *msg) {
   // so the important thing about dump() is that
   // we are working with bit patterns in memory we
   // do not own, and it is memory we did not set (at least
   // not here in dump(), the caller is manipulating the bit
   // patterns for the 2 bytes in location 'a').
   cout << "===== " << msg << " =====\n";
   cout << "a=" << dec << a << "(dec), 0x" << hex << a << dec << " (address of a: " << &a << ")\n";
   cout << "c1=" << (void *)c1 << " (should be the same as 'address of a')\n";
   cout << "c2=" << (void *)c2 << " (should be just 1 more than 'address of a')\n";
   cout << "c1=" << (char)(*c1) << "\n";
   cout << "c2=" << (char)(*c2) << "\n";
   cout << "in hex, c1=" << hex << ((int)(*c1)) << dec << "\n";
   cout << "in hex, c2=" << hex << (int)(*c2) << dec << "\n";
}

int main() {
   cout << "sizeof char =" << sizeof( char  ) << ", unsigned char =" << sizeof( unsigned char  ) << "\n";
   cout << "sizeof short=" << sizeof( short ) << ", unsigned short=" << sizeof( unsigned short ) << "\n";
   cout << "sizeof int  =" << sizeof( int   ) << ", unsigned int  =" << sizeof( unsigned int   ) << "\n";
   cout << "sizeof long =" << sizeof( long  ) << ", unsigned long =" << sizeof( unsigned long  ) << "\n";

   // this logic changes the bit pattern in a then calls dump() to interpret that bit pattern.
   a = (0x41<<8) + 0x42; dump( "In ASCII, 0x41 is 'A' and 0x42 is 'B'" );
   a+= 1;                dump( "after a+= 1" );
   a+= 5;                dump( "after a+= 5" );
   a = (0x58<<8) + 0x59; dump( "In ASCII, 0x58 is 'X' and 0x42 is 'Y'" );
   a = (0x59<<8) + 0x5A; dump( "In ASCII, 0x59 is 'Y' and 0x5A is 'Z'" );

   cout << "Done.\n";

}

===结束示例程序===

答案 4 :(得分:0)

int 是一个整数,小数点后没有数字的数字。它可以是正面的或负面的。在内部,整数存储为二进制数。在大多数计算机上,整数是32位二进制数,但是这个大小可能因计算机而异。使用整数进行计算时,小数点后的任何内容都将丢失。因此,如果您将2除以3,则结果为0,而不是0.6666。

char 是一种用于保存字符的数据类型,如字母数字字符串。此数据类型可以是正数或负数,即使使用它的大多数字符数据都是无符号的。 char的典型大小是一个字节(八位),但这在一台机器之间有所不同。在支持宽字符(例如,Unicode)或字符串的多字节编码方案的机器上,该图显着增厚。但一般来说char是一个字节。