GetPrivateProfileString - 缓冲区长度

时间:2012-05-08 23:26:49

标签: winapi ini

Windows'GetPrivateProfileXXX函数(用于处理INI文件)有一些关于处理缓冲区长度的奇怪规则。

GetPrivateProfileString的文档说明:

  

如果[..]提供的目标缓冲区太小而无法保存请求的字符串,则字符串将被截断,后跟空字符,返回值等于nSize减去1。

我读了这篇文章,我意识到这种行为使得无法区分代码中的两种情况:

  • 当值字符串的长度恰好等于nSize - 1时。
  • 当nSize值(即缓冲区)太小时。

我以为我要做实验:

我在INI文件中有这个:

[Bar]
foo=123456

我用这些参数调用了GetPrivateProfileString作为测试:

// Test 1. The buffer is big enough for the string (16 character buffer).
BYTE* buffer1 = (BYTE*)calloc(16, 2); // using 2-byte characters ("Unicode")
DWORD result1 = GetPrivateProfileString(L"Bar", L"foo", NULL, buffer, 16, fileName);

// result1 is 6
// buffer1 is { 49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 54, 0, 0, 0, 0, 0, ... , 0, 0 }

// Test 2. The buffer is exactly sufficient to hold the value and the trailing null (7 characters).
BYTE* buffer2 = (BYTE*)calloc(7, 2);
DWORD result2 = GetPrivateProfileString(L"Bar", L"foo", NULL, buffer, 7, fileName);

// result2 is 6. This is equal to 7-1.
// buffer2 is { 49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 54, 0, 0, 0 }

// Test 3. The buffer is insufficient to hold the value and the trailing null (6 characters).
BYTE* buffer3 = (BYTE*)calloc(6, 2);
DWORD result3 = GetPrivateProfileString(L"Bar", L"foo", NULL, buffer, 6, fileName);

// result3 is 5. This is equal to 6-1.
// buffer3 is { 49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 0, 0 }

调用此代码的程序无法确定实际的键值是否确实长度为5个字符,甚至是6个字符,因为在最后两个案例中结果等于nSize - 1.

唯一的解决方案是检查result == nSize - 1并使用更大的缓冲区调用该函数,但在缓冲区大小合适的情况下这是不必要的。

有没有更好的方法?

6 个答案:

答案 0 :(得分:4)

没有更好的方法。试着确保第一个缓冲区足够大。解决这个问题的任何方法都必须使用文档中没有描述的内容,因此无法保证工作。

答案 1 :(得分:1)

不,不幸的是,没有更好的方法。你必须提供足够大的缓冲区。如果还不够,请重新分配缓冲区。我从here获取了代码段,并根据您的情况进行了调整:

int nBufferSize = 1000;
int nRetVal;
int nCnt = 0;
BYTE* buffer = (BYTE*)calloc(1, 2); 

do
{
    nCnt++;
      buffer = (BYTE*) realloc (buffer , nBufferSize * 2 * nCnt);
      DWORD nRetVal = GetPrivateProfileString(L"Bar", L"foo", NULL,         
            buffer, nBufferSize*nCnt, filename);    
} while( (nRetVal == ((nBufferSize*nCnt) - 1)) || 
            (nRetVal == ((nBufferSize*nCnt) - 2)) );

但是,在您的特定情况下,文件名的长度不能超过MAX_PATH,因此(MAX_PATH+1)*2将始终适合。

答案 2 :(得分:1)

当我在努力将一些旧代码带入未来时,我发现了有关缓冲和私有配置文件API的问题。经过我自己的实验和研究,我可以确认asker最初的说法,即无法确定字符串确切是nSize-1还是缓冲区太小之间的差异。

有更好的方法吗? Mike接受的答案说,没有根据文档的说明,您应该只是尝试,以确保缓冲区足够大。马克说要增加缓冲区。罗曼说检查错误代码。某些随机用户说,您需要提供足够大的缓冲区,并且与Marc不同,它继续显示一些扩展缓冲区的代码。

有更好的方法吗?让我们得到事实吧!

由于ProfileString API的年代久远,因为此问题的所有标记均不涉及任何特定语言,并且为了易于阅读,所以我决定使用VB6展示示例。可以根据自己的目的随意翻译它们。


GetPrivateProfileString文档

根据GetPrivateProfileString documentation,提供这些专用配置文件功能仅是为了与基于Windows的16位应用程序兼容。这是非常有用的信息,因为它使我们能够了解这些API函数可以执行的操作的局限性。

16位带符号整数的范围是-32,768到32,767,而无符号16位整数的范围是0到65,535。如果这些功能是真正为在16位环境中使用而设计的,那么我们遇到的任何数字很可能都将被限制为这两个限制之一。

文档指出,返回的每个字符串都将以空字符结尾,并且还说不适合所提供缓冲区的字符串将被截断并以空字符终止。因此,如果字符串确实适合缓冲区,则倒数第二个字符以及最后一个字符也将为null。如果只有最后一个字符为null,则提取的字符串与提供的缓冲区长度完全相同-1或缓冲区的大小不足以容纳该字符串。

在倒数第二个字符都不为空(提取的字符串是缓冲区的确切长度或太大)的情况下,GetLastError将返回错误号234 ERROR_MORE_DATA (0xEA),这使我们无法区分它们。

>

GetPrivateProfileString接受的最大缓冲区大小是多少?

尽管文档未说明最大缓冲区大小,但我们已经知道此API是为16位环境设计的。经过一些试验,我可以得出最大缓冲区大小为 65,536 的结论。如果文件中的字符串长于65,535个字符,那么在尝试读取字符串时,我们会开始看到一些奇怪的行为。如果文件中的字符串长65,536个字符,则检索到的字符串长为0个字符。如果文件中的字符串长度为65,546个字符,则检索到的字符串将为10个字符长,以空字符结尾,并从文件中包含的字符串的开头开始就被截断。该API将写入一个大于65,535个字符的字符串,但不能读取大于65,535个字符的任何字符。如果缓冲区长度为65,536,并且文件中的字符串长度为65,535个字符,则缓冲区将包含文件中的字符串,并以单个空字符结尾。

这为我们提供了第一个虽然不是完美的解决方案。如果要始终确保第一个缓冲区足够大,请将该缓冲区设置为65,536个字符长。

Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long

Public Function iniRead(ByVal Pathname As String, ByVal Section As String, ByVal Key As String, Optional ByVal Default As String) As String
    On Error GoTo iniReadError
    Dim Buffer As String
    Dim Result As Long
    Buffer = String$(65536, vbNullChar)
    Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, 65536, Pathname)
    If Result <> 0 Then
        iniRead = Left$(Buffer, Result)
    Else
        iniRead = Default
    End If
iniReadError:
End Function

现在我们知道最大缓冲区大小,我们可以使用文件的大小进行修改。如果文件大小少于65,535个字符,则可能没有理由创建如此大的缓冲区。

在文档的备注部分中,它说初始化文件中的一部分必须具有以下格式:

  

[section]
key = string

我们可以假设每个部分包含两个方括号和一个等号。经过一个小的测试,我能够验证该API将接受该部分和键(vbLf,vbCr或vbCrLf / vbNewLine)之间的任何换行符。这些详细信息以及节和键名的长度,将使我们能够缩小最大缓冲区长度,并确保在尝试读取文件之前,文件的大小足以包含一个字符串。

Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long

Public Function iniRead(ByVal Pathname As String, ByVal Section As String, ByVal Key As String, Optional ByVal Default As String) As String
    On Error Resume Next
    Dim Buffer_Size As Long
    Err.Clear
    Buffer_Size = FileLen(Pathname)
    On Error GoTo iniReadError
    If Err.Number = 0 Then
        If Buffer_Size > 4 + Len(Section) + Len(Key) Then
            Dim Buffer As String
            Dim Result As Long
            Buffer_Size = Buffer_Size - Len(Section) - Len(Key) - 4
            If Buffer_Size > 65535 Then
                Buffer_Size = 65536
            Else
                Buffer_Size = Buffer_Size + 1
            End If
            Buffer = String$(Buffer_Size, vbNullChar)
            Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
            If Result <> 0 Then
                iniRead = Left$(Buffer, Result)
                Exit Function
            End If
        End If
    End If
    iniRead = Default
iniReadError:
End Function

增加缓冲区

现在,我们已经非常努力地确保第一个缓冲区足够大,并且我们已修改了最大缓冲区大小,从较小的缓冲区开始逐渐增大缓冲区的大小对于我们来说还是有意义的缓冲区以创建足够大的缓冲区,以便我们可以从文件中提取整个字符串。根据文档,API会创建234错误,以告诉我们还有更多可用数据。他们使用此错误代码来告诉我们使用更大的缓冲区再试是很有意义的。一遍又一遍地重试的缺点是它的成本更高。文件中的字符串越长,读取它所需的尝试越多,花费的时间也越长。对于当今的计算机而言,64 KB并不多,并且当今的计算机还算快,因此无论如何,您可能会发现这两个示例都适合您的目的。

我已经对GetPrivateProfileString API进行了相当多的搜索,并且我发现,通常当对API不了解的人尝试创建足够大的缓冲区来满足他们的需求时,他们选择的缓冲区长度为255。这样一来,您就可以从文件中读取最多254个字符的字符串。我不确定为什么有人开始使用它,但是我会假设有人在想像这个API使用的字符串,其中缓冲区长度限制为8位无符号数。也许这是WIN16的局限性。

除非缓冲区的最大长度小于最小值,否则我将以64字节的低位开始缓冲区,然后将该数字加倍,直到最大缓冲区长度或65,536。将数字加倍也是可以接受的,较大的乘法意味着较少的尝试读取较大字符串的文件,而相对而言,某些中等长度的字符串可能会有额外的填充。

Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long

Public Function iniRead(ByVal Pathname As String, ByVal Section As String, ByVal Key As String, Optional ByVal Default As String) As String
    On Error Resume Next
    Dim Buffer_Max As Long
    Err.Clear
    Buffer_Max = FileLen(Pathname)
    On Error GoTo iniReadError
    If Err.Number = 0 Then
        If Buffer_Max > 4 + Len(Section) + Len(Key) Then
            Dim Buffer As String
            Dim Result As Long
            Dim Buffer_Size As Long
            Buffer_Max = Buffer_Max - Len(Section) - Len(Key) - 4
            If Buffer_Max > 65535 Then
                Buffer_Max = 65536
            Else
                Buffer_Max = Buffer_Max + 1
            End If
            If Buffer_Max < 64 Then
                Buffer_Size = Buffer_Max
            Else
                Buffer_Size = 64
            End If
            Buffer = String$(Buffer_Size, vbNullChar)
            Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
            If Result <> 0 Then
                If Buffer_Max > 64 Then
                    Do While Result = Buffer_Size - 1 And Buffer_Size < Buffer_Max
                        Buffer_Size = Buffer_Size * 4
                        If Buffer_Size > Buffer_Max Then
                            Buffer_Size = Buffer_Max
                        End If
                        Buffer = String$(Buffer_Size, vbNullChar)
                        Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
                    Loop
                End If
                iniRead = Left$(Buffer, Result)
                Exit Function
            End If
        End If
    End If
    iniRead = Default
iniReadError:
End Function

改进的验证

根据您的实现方式,改进对路径名,节和键名的验证可能会阻止您需要准备缓冲区。

根据Wikipedia's INI File page,他们说:

  

在Windows实现中,键不能包含字符   等号(=)或半冒号(;),因为它们是保留字符。   该值可以包含任何字符。

  

在Windows实现中,该部分不能包含字符   右括号(])。

对GetPrivateProfileString API的快速测试证明这仅部分正确。只要在键名的开头就没有半角冒号,我就没有问题。他们没有在文档或Wikipedia中提及任何其他限制,尽管可能还有更多限制。

另一个快速测试来查找GetPrivateProfileString接受的节或键名的最大长度,这给了我65,535个字符的限制。使用大于65,535个字符的字符串的效果与测试最大缓冲区长度时所经历的效果相同。另一项测试证明此API将接受段或键名的空白字符串。根据API的功能,这是一个可接受的初始化文件:

  

[]
  =世界你好!

根据Wikipedia,对空格的解释各不相同。经过另一项测试之后,Profile String API肯定会从节和键名中删除空格,因此如果我们也这样做也可以。

Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long

Public Function iniRead(ByVal Pathname As String, ByVal Section As String, ByVal Key As String, Optional ByVal Default As String) As String
    On Error Resume Next
    If Len(Pathname) <> 0 Then
        Key = Trim$(Key)
        If InStr(1, Key, ";") <> 1 Then
            Section = Trim$(Section)
            If Len(Section) > 65535 Then
                Section = RTrim$(Left$(Section, 65535))
            End If
            If InStr(1, Section, "]") = 0 Then
                If Len(Key) > 65535 Then
                    Key = RTrim$(Left$(Key, 65535))
                End If
                If InStr(1, Key, "=") = 0 Then
                    Dim Buffer_Max As Long
                    Err.Clear
                    Buffer_Max = FileLen(Pathname)
                    On Error GoTo iniReadError
                    If Err.Number = 0 Then
                        If Buffer_Max > 4 + Len(Section) + Len(Key) Then
                            Dim Buffer As String
                            Dim Result As Long
                            Dim Buffer_Size As Long
                            Buffer_Max = Buffer_Max - Len(Section) - Len(Key) - 4
                            If Buffer_Max > 65535 Then
                                Buffer_Max = 65536
                            Else
                                Buffer_Max = Buffer_Max + 1
                            End If
                            If Buffer_Max < 64 Then
                                Buffer_Size = Buffer_Max
                            Else
                                Buffer_Size = 64
                            End If
                            Buffer = String$(Buffer_Size, vbNullChar)
                            Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
                            If Result <> 0 Then
                                If Buffer_Max > 64 Then
                                    Do While Result = Buffer_Size - 1 And Buffer_Size < Buffer_Max
                                        Buffer_Size = Buffer_Size * 4
                                        If Buffer_Size > Buffer_Max Then
                                            Buffer_Size = Buffer_Max
                                        End If
                                        Buffer = String$(Buffer_Size, vbNullChar)
                                        Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
                                    Loop
                                End If
                                iniRead = Left$(Buffer, Result)
                                Exit Function
                            End If
                        End If
                    End If
                    iniRead = Default
                End If
            End If
        End If
    End If
iniReadError:
End Function

静态长度缓冲区

有时我们需要存储具有最大长度或静态长度的变量。用户名,电话号码,颜色代码或IP地址是您可能希望限制最大缓冲区长度的字符串示例。必要时这样做可以节省您的时间和精力。

在下面的代码示例中,Buffer_Max将被限制为Buffer_Limit +1。如果该限制大于64,我们将从64开始并像以前一样扩展缓冲区。少于64,并且使用新的缓冲区限制,我们只会读取一次。

Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long

Public Function iniRead(ByVal Pathname As String, ByVal Section As String, ByVal Key As String, Optional ByVal Default As String, Optional Buffer_Limit As Long = 65535) As String
    On Error Resume Next
    If Len(Pathname) <> 0 Then
        Key = Trim$(Key)
        If InStr(1, Key, ";") <> 1 Then
            Section = Trim$(Section)
            If Len(Section) > 65535 Then
                Section = RTrim$(Left$(Section, 65535))
            End If
            If InStr(1, Section, "]") = 0 Then
                If Len(Key) > 65535 Then
                    Key = RTrim$(Left$(Key, 65535))
                End If
                If InStr(1, Key, "=") = 0 Then
                    Dim Buffer_Max As Long
                    Err.Clear
                    Buffer_Max = FileLen(Pathname)
                    On Error GoTo iniReadError
                    If Err.Number = 0 Then
                        If Buffer_Max > 4 + Len(Section) + Len(Key) Then
                            Dim Buffer As String
                            Dim Result As Long
                            Dim Buffer_Size As Long
                            Buffer_Max = Buffer_Max - Len(Section) - Len(Key) - 4
                            If Buffer_Limit > 65535 Then
                                Buffer_Limit = 65535
                            End If
                            If Buffer_Max > Buffer_Limit Then
                                Buffer_Max = Buffer_Limit + 1
                            Else
                                Buffer_Max = Buffer_Max + 1
                            End If
                            If Buffer_Max < 64 Then
                                Buffer_Size = Buffer_Max
                            Else
                                Buffer_Size = 64
                            End If
                            Buffer = String$(Buffer_Size, vbNullChar)
                            Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
                            If Result <> 0 Then
                                If Buffer_Max > 64 Then
                                    Do While Result = Buffer_Size - 1 And Buffer_Size < Buffer_Max
                                        Buffer_Size = Buffer_Size * 4
                                        If Buffer_Size > Buffer_Max Then
                                            Buffer_Size = Buffer_Max
                                        End If
                                        Buffer = String$(Buffer_Size, vbNullChar)
                                        Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
                                    Loop
                                End If
                                iniRead = Left$(Buffer, Result)
                                Exit Function
                            End If
                        End If
                    End If
                    iniRead = Default
                End If
            End If
        End If
    End If
iniReadError:
End Function

使用WritePrivateProfileString

要确保使用GetPrivateProfileString读取字符串没有问题,请在使用WritePrivateProfileString之前很长时间将字符串限制为65,535个字符或更少。包含相同的验证也是一个好主意。

Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long
Private Declare Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpString As Any, ByVal lpFileName As String) As Long

Public Function iniRead(ByVal Pathname As String, ByVal Section As String, ByVal Key As String, Optional ByVal Default As String, Optional Buffer_Limit As Long = 65535) As String
    On Error Resume Next
    If Len(Pathname) <> 0 Then
        Key = Trim$(Key)
        If InStr(1, Key, ";") <> 1 Then
            Section = Trim$(Section)
            If Len(Section) > 65535 Then
                Section = RTrim$(Left$(Section, 65535))
            End If
            If InStr(1, Section, "]") = 0 Then
                If Len(Key) > 65535 Then
                    Key = RTrim$(Left$(Key, 65535))
                End If
                If InStr(1, Key, "=") = 0 Then
                    Dim Buffer_Max As Long
                    Err.Clear
                    Buffer_Max = FileLen(Pathname)
                    On Error GoTo iniReadError
                    If Err.Number = 0 Then
                        If Buffer_Max > 4 + Len(Section) + Len(Key) Then
                            Dim Buffer As String
                            Dim Result As Long
                            Dim Buffer_Size As Long
                            Buffer_Max = Buffer_Max - Len(Section) - Len(Key) - 4
                            If Buffer_Limit > 65535 Then
                                Buffer_Limit = 65535
                            End If
                            If Buffer_Max > Buffer_Limit Then
                                Buffer_Max = Buffer_Limit + 1
                            Else
                                Buffer_Max = Buffer_Max + 1
                            End If
                            If Buffer_Max < 64 Then
                                Buffer_Size = Buffer_Max
                            Else
                                Buffer_Size = 64
                            End If
                            Buffer = String$(Buffer_Size, vbNullChar)
                            Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
                            If Result <> 0 Then
                                If Buffer_Max > 64 Then
                                    Do While Result = Buffer_Size - 1 And Buffer_Size < Buffer_Max
                                        Buffer_Size = Buffer_Size * 4
                                        If Buffer_Size > Buffer_Max Then
                                            Buffer_Size = Buffer_Max
                                        End If
                                        Buffer = String$(Buffer_Size, vbNullChar)
                                        Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
                                    Loop
                                End If
                                iniRead = Left$(Buffer, Result)
                                Exit Function
                            End If
                        End If
                    End If
                    iniWrite Pathname, Section, Key, Default
                    iniRead = Default
                End If
            End If
        End If
    End If
iniReadError:
End Function

Public Function iniWrite(ByVal Pathname As String, ByVal Section As String, ByVal Key As String, ByVal Value As String) As Boolean
    On Error GoTo iniWriteError
    If Len(Pathname) <> 0 Then
        Key = Trim$(Key)
        If InStr(1, Key, ";") <> 1 Then
            Section = Trim$(Section)
            If Len(Section) > 65535 Then
                Section = RTrim$(Left$(Section, 65535))
            End If
            If InStr(1, Section, "]") = 0 Then
                If Len(Key) > 65535 Then
                    Key = RTrim$(Left$(Key, 65535))
                End If
                If InStr(1, Key, "=") = 0 Then
                    If Len(Value) > 65535 Then Value = Left$(Value, 65535)
                    iniWrite = WritePrivateProfileString(Section, Key, Value, Pathname) <> 0
                End If
            End If
        End If
    End If
iniWriteError:
End Function

答案 3 :(得分:0)

也许,在GetLastError之后调用GetPrivateProfileString是一种方法。如果缓冲区足够大并且没有其他错误,GetLastError将返回0.如果缓冲区太小,GetLastError将返回234 (0xEA) ERROR_MORE_DATA

答案 4 :(得分:0)

我知道这有点晚了,但我想出了一个很棒的解决方案。如果没有剩余缓冲区空间(返回长度+ 1 =缓冲区长度),则增大缓冲区并再次获取值。重复该过程,直到剩余缓冲区为止。

答案 5 :(得分:-1)

最好的解决方案肯定是Brogan,但是检查文件大小作为缓冲区大小的上限是错误的。尤其是在处理位于Windows或系统文件夹中的INI文件时,许多注册表项已映射为要在注册表中读取和/或写入。 映射结构可以在以下位置找到:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping

有关其工作原理的完整说明,请阅读Remarks section of the GetPrivateProfileString documentation

因此,您可能有许多重新映射到注册表的字符串,这些字符串长了足够长的时间,但是磁盘上有一个小的INI文件。在这种情况下,解决方案将无法读取。

当不使用所需文件的绝对路径或它不在程序的当前工作目录中时,该解决方案还有一个小问题,因为GetPrivateProfileStrings在Windows目录中搜索初始化文件。 FileLen函数中没有此操作,解决方案也没有对此进行检查。

最终分配了64K内存并接受此限制。