空终止字符串与x86汇编语言中未以null终止的字符串之间有何不同

时间:2017-06-27 00:41:44

标签: string assembly null x86 masm

我目前正在学习汇编编程,遵循Kip Irvine的“汇编语言x86编程”一书。

在书中,作者陈述

  

最常见的字符串类型以空字节(包含0)结尾。   称为以null结尾的字符串

在本书的后续部分中,作者有一个不带空字节的字符串示例

greeting1 \
BYTE "Welcome to the Encryption Demo program "

所以我只是想知道,在x86汇编语言中,空终止字符串和未以null终止的字符串之间有什么不同?它们可以互换吗?或者他们不相同?

2 个答案:

答案 0 :(得分:4)

这里没有什么特别的东西;它与C中的问题相同。它是关于如何将字符串存储在内存中并跟踪它们的结束位置。

  

空终止字符串与未以null终止的字符串之间有什么不同?

以null结尾的字符串后面有一个0字节,因此您可以找到strlen的结尾。 (或rep scasb)。这可以用作隐式长度字符串,如C使用。

  

它们可以互换吗?

如果知道以null结尾的字符串的长度,则可以将指针+长度传递给需要显式长度字符串的函数。该函数永远不会查看0字节,因为您将传递一个不包含0字节的长度。它不属于正确的字符串数据。

但是如果你有一个没有终结符的字符串,你就不能将它传递给想要以空字符结尾的字符串的函数或系统调用。 (如果内存是可写的,您可以在字符串后面存储0,使其成为以空字符结尾的字符串。)

在Linux中,许多系统调用将字符串作为C样式的隐式长度以空字符结尾的字符串。 (即只是char*而没有通过长度。)

例如,open(2)为路径采用字符串:int open(const char *pathname, int flags);必须将以null结尾的字符串传递给系统调用。在Linux中创建一个名为包含'\0'的文件是不可能的(与大多数其他Unix系统相同),因为处理文件的所有系统调用都使用以空字符结尾的字符串。

OTOH,write(2)占用的内存缓冲区不一定是字符串。它有签名ssize_t write(int fd, const void *buf, size_t count);。它并不关心0 buf+count是否buf因为它只查看从buf+count-1write()的字节。

可以将字符串传递给open()。它并不关心。它基本上只是内核页面缓存的内存(或者是管道缓冲区或非常规文件的内容)。但就像我说的那样,你不能通过一个任意的非终止缓冲区作为O(n)的路径arg。

  

或者他们不相同?

隐式长度和显式长度是在内存中跟踪字符串数据/常量并传递它们的两种主要方法。他们以相反的方式解决了同样的问题。

如果您有时需要在遍历它们之前找到它们的长度,那么长隐式长度字符串是一个糟糕的选择。循环遍历字符串比读取整数慢得多。查找隐式长度字符串的长度为O(1),但显式长度字符串当然是{{1}}时间来查找长度。 (它已经知道了!)。至少以字节为单位的长度是已知的,但如果Unicode字符的长度是UTF-8或UTF-16等可变长度编码,则可能不知道它的长度。

答案 1 :(得分:2)

字符串的终止方式与汇编无关。从历史上看,' $',CRLF [10,13]或[0A,0D]有时与Linux下的GEDIT相反。约定取决于您的系统如何与自身或其他系统进行交互。例如,我的应用程序严格遵循ASCII,因此,如果我读取一个UTF-8或16的文件,我的应用程序将失败。 NULL或任何类型的终止都是可选的。

考虑这个例子

Title:  db  'Proto_Sys 1.00.0', 0, 0xc4, 0xdc, 0xdf, 'CPUID', 0, 'A20', 0
        db  'AXCXDXBXSPBPSIDIESDSCSSSFSGS'
Err00:  db  'Retry [Y/N]', 0

我已经实现了一个例程,如果CX = 0,那么它将假设显示一个以NULL结尾的字符串,否则只读取一个字符并重复CX次。这就是 0xc4 0xdc 0xdf 未终止的原因。同样,在' 重试[Y / N] '之前,还没有终结者。因为我的算法的设计方式,并不是必须的。

您唯一需要关心的是您的数据来源是什么,或者您的应用程序是否需要与其他内容兼容。然后,您只需实现您需要的任何工作。