为什么编译器坚持我的功能是内联的,当它不是? [英] Why does the compiler insist my function is inline when it's not?

查看:244
本文介绍了为什么编译器坚持我的功能是内联的,当它不是?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么我收到


[DCC错误] ProjectCOWArray.dpr(23):E2426内联函数不能有asm块




 程序ProjectCOWArray; 

{$ APPTYPE CONSOLE}

{$ R * .res}

type
PRefCount = ^ TRefCount;
TRefCount = array [0..1] of integer;


TCOWArray< T> = record
private
fData:TArray< T>
private
procedure IncRefCount; << - not inline
end;


{TCOWArray< T> }

procedure TCOWArray< T> .IncRefCount;
asm
{$ if defined(win32)}
mov eax,fData;
lock inc dword ptr [eax - 8];
{$ ifend}
{$ if defined(win64)}
mov rax,fData;
lock inc dword ptr [rax -12];
{$ ifend}
end;

begin
end。

Delphi XE2没有 AtomicIncrement 我如何解决这个问题?

它想保留汇编器,因为否则我不能有前缀,我不想使用 InterlockedIncrement ,因为这是一个WinAPI函数,我不想那种开销。

解决方案

这是因为泛型功能是在内联引擎之上实现的。适用于内联函数的相同限制适用于通用函数。编译器写程序没有采取额外的步骤来使错误消息特定于泛型而不是内联函数。



我认为调用 InterlockedIncrement 可能是最好的选择,对于没有 AtomicIncrement 内在。或者,创建自己的版本 AtomicIncrement ,这只是在Delphi的版本中定义的,不包括它。这个函数可以写成asm。当然,它显然必须用asm写。

  {$ IFNDEF AtomicFunctionsAvailable} 
function AtomicIncrement目标:整数):整数;
asm
....
end;
{$ ENDIF}

或者如@TLama建议,您可以使用<$ c $

使用 System.SyncObjs 单元中的 TInterlocked 所有的说,我看不需要以这种方式介入内部。每当您写入数组时,通过调用 SetLength(...)实现写数组的副本。例如,这里有一个非常简单的写数组实现的副本:

 单元COWArray; 

interface

type
TCOWArray< T> = record
private
FItems:TArray< T>
function GetLength:Integer;
procedure SetLength(Value:Integer);
function GetItem(Index:Integer):T;
procedure SetItem(Index:Integer; const Value:T);
public
类函数New(const Values:T的数组):TCOWArray< T>静态的;
属性长度:整数读取GetLength write SetLength;
属性Items [索引:Integer]:T读取GetItem write SetItem;默认;
end;

实现

function TCOWArray< T> .GetLength:Integer;
begin
结果:= System.Length(FItems);
end;

procedure TCOWArray< T> .SetLength(Value:Integer);
begin
System.SetLength(FItems,Value); // SetLength enforces uniqueness
end;

function TCOWArray< T> .GetItem(Index:Integer):T;
begin
结果:= FITEMs [Index];
end;

procedure TCOWArray< T> .SetItem(Index:Integer; const Value:T);
begin
System.SetLength(FItems,System.Length(FItems)); // SetLength enforces uniqueness
FItems [Index]:= Value;
end;

类函数TCOWArray< T> .New(const Values:T array):TCOWArray< T>
var
i:Integer;
begin
System.SetLength(Result.FItems,System.Length(Values));
for i:= 0 to high(Values)do
Result.FItems [i]:= Values [i];
end;

end。


Why am I getting

[DCC Error] ProjectCOWArray.dpr(23): E2426 Inline function must not have asm block

program ProjectCOWArray;

{$APPTYPE CONSOLE}

{$R *.res}

type
  PRefCount = ^TRefCount;
  TRefCount = array[0..1] of integer;


  TCOWArray<T> = record
  private
    fData: TArray<T>;
  private
    procedure IncRefCount;  <<-- not inline  
  end;


{ TCOWArray<T> }

procedure TCOWArray<T>.IncRefCount;
asm
  {$if defined(win32)}
  mov eax,fData;
  lock inc dword ptr [eax - 8];
  {$ifend}
  {$if defined(win64)}
  mov rax,fData;
  lock inc dword ptr[rax -12];
  {$ifend}
end;

begin
end.

Delphi XE2 does not have AtomicIncrement, so how do I solve this issue?
It'd like to retain the assembler, because otherwise I cannot have the lock prefix in and I do not want to use InterlockedIncrement because that's a WinAPI function and I do not want that kind of overhead.

解决方案

This is because the generics functionality is implemented on top of the inlining engine. The same restrictions that apply to inline functions apply to generic functions. The compiler writers just haven't taken the extra step to make the error messages specific to generics rather than inline functions.

I think that calling InterlockedIncrement is probably your best option, for Delphi versions that don't have the AtomicIncrement intrinsic. Or, alternatively, create your own version of AtomicIncrement, that is only defined in versions of Delphi that do not include it. And that function can be written in asm. Well, it clearly has to be written in asm of course.

{$IFNDEF AtomicFunctionsAvailable}
function AtomicIncrement(var Target: Integer): Integer;
asm
  ....
end;
{$ENDIF}

Or as @TLama suggests, you can use TInterlocked from the System.SyncObjs unit to provide atomic operations.

With all that said, I see no need to meddle with the internals in this way. Implement a copy of write array by calling SetLength(...) whenever you write to the array. For instance, here's a very simple copy on write array implementation:

unit COWArray;

interface

type
  TCOWArray<T> = record
  private
    FItems: TArray<T>;
    function GetLength: Integer;
    procedure SetLength(Value: Integer);
    function GetItem(Index: Integer): T;
    procedure SetItem(Index: Integer; const Value: T);
  public
    class function New(const Values: array of T): TCOWArray<T>; static;
    property Length: Integer read GetLength write SetLength;
    property Items[Index: Integer]: T read GetItem write SetItem; default;
  end;

implementation

function TCOWArray<T>.GetLength: Integer;
begin
  Result := System.Length(FItems);
end;

procedure TCOWArray<T>.SetLength(Value: Integer);
begin
  System.SetLength(FItems, Value); // SetLength enforces uniqueness
end;

function TCOWArray<T>.GetItem(Index: Integer): T;
begin
  Result := FItems[Index];
end;

procedure TCOWArray<T>.SetItem(Index: Integer; const Value: T);
begin
  System.SetLength(FItems, System.Length(FItems)); // SetLength enforces uniqueness
  FItems[Index] := Value;
end;

class function TCOWArray<T>.New(const Values: array of T): TCOWArray<T>;
var
  i: Integer;
begin
  System.SetLength(Result.FItems, System.Length(Values));
  for i := 0 to high(Values) do
    Result.FItems[i] := Values[i];
end;

end.

这篇关于为什么编译器坚持我的功能是内联的,当它不是?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆