通过PAnsiChar(char *)传递AnsiString是否明确需要null终止符?

时间:2014-05-27 05:41:59

标签: c++ c delphi dll null

在这里和interop和C(++)是新的,我确实在这个问题上搜索答案,但在SO或www上找不到。我缺乏选择正确的单词来寻找答案,或者我错过了这个非常基本的问题......

使用Delphi dll和' C(++)dll调用者之间的互操作,您是否在Delphi dll中明确声明空终止符字符以传递给dll调用者?

e.g。 Dll调用者(C代码)

char ErrorMessage[10];
(*GetMessageFromDLLFunction)(&ErrorMessage[0], 10); // (char * ErrorMessage, int buffSize)

Dll代码(Delphi):

GetMessageFromDLLFunction(errorMessage: PAnsiChar; buffSize: Integer)

// What if the message generated in this function exceeds 10 characters?
// do I return 9 characters and a null terminator?
tmpMessage := SetLength(tmpMessage, buffSize-1);
tmpMessage := tmpMessage + #0;
System.AnsiStrings.StrCopy(errorMessage,PAnsiChar(tmpMessage));

// or do I return 9 characters without an explicit null terminator?
tmpMessage := SetLength(tmpMessage, buffSize-1);
System.AnsiStrings.StrCopy(errorMessage,PAnsiChar(tmpMessage));

什么是最佳/正确的做法?

2 个答案:

答案 0 :(得分:3)

如果您返回的字符串有时以空值终止,有时不会,则会给调用者带来沉重的复杂负担。调用者有时必须添加null终止符。并且调用者面临着将字符串放在缓冲区中的尴尬情况,该缓冲区是一个字符太短而不能包含空终止符。通常最好将复杂性降低到尽可能低的水平,所以我的感觉是,在所有条件相同的情况下,你应该总是返回一个以null结尾的缓冲区。

您目前的代码不会尝试通知用户存储完整字符串需要多大的缓冲区。您可以继续这种方式,但我绝对建议您确保返回的值始终以null结尾。这看起来像这样:

function GetString(Buffer: PAnsiChar; Len: Integer): Integer;
var
  Value: AnsiString;
begin
  if Len < 1 then
  begin
    Result := STATUS_INVALID_PARAMETER;
    exit;
  end;

  Value := ... // get the string to be returned somehow
  StrLCopy(Buffer, PAnsiChar(Value), Len - 1);
  if Length(Value) < Len then
    Result := STATUS_OK
  else
    Result := STATUS_BUFFER_TOO_SHORT;
end;

或者,您可以修改接口以让调用者知道需要多大的缓冲区。这可能是这样的:

function GetString(Buffer: PAnsiChar; var Len: Integer): Integer;
var
  Value: AnsiString;
begin
  if Len < 0 then
  begin
    Result := STATUS_INVALID_PARAMETER;
    exit;
  end;

  Value := ... // get the string to be returned somehow
  if Len > 0 then
    StrLCopy(Buffer, PAnsiChar(Value), Len - 1);
  if Length(Value) < Len then
    Result := STATUS_OK
  else
    Result := STATUS_BUFFER_TOO_SHORT;
  Len := Length(Value) + 1;
end;

答案 1 :(得分:2)

完全取决于你自己决定。由于您将缓冲区长度作为输入传递,因此您可以采用任何一种方式。但是如果您选择在输出中省略null,则应该让函数返回实际写入缓冲区的字符数,以便调用者知道停止读取的位置。如果完整的消息很重要,您甚至可以返回错误而不是让调用者知道缓冲区太小而无法接收完整输出。