Чтение и назначение параметра пустого типа

StackOverflow https://stackoverflow.com/questions/1100490

  •  11-09-2019
  •  | 
  •  

Вопрос

Я написал два метода с параметром пустого типа:

procedure Method1(const MyVar; size: cardinal);
var
  Arr: array of byte;
begin
  SetLength(Arr, size);
  {now copy the data from MyVar to Arr, but how?}  
end;

procedure Method2(var MyVar; size: cardinal);
var
  Arr: array of byte;
begin
  SetLength(Arr, size);
  {return the data from the array, but how?}
end;

В первом я хотел бы получить доступ к Myvar как массив байта. Во втором я хотел бы скопировать данные из локального массива Arr в Myvar. Поэтому я использовал функцию CopyMemory (), но с ней что -то не так.

Если я использую следующее во втором методе, это нормально, если метод2 вызывается с массивом в качестве параметра (метод2 (указатель (mystring)^, длина (mystring)) или метод2 (указатель (myarray), длина (myarray ))).

CopyMemory(Pointer(MyVar), Pointer(Arr), size);

Если я звоню Method2 с помощью A, например, Integer Parameter (Method2 (myIinteger, sizeof (myIinteger))), он не работает должным образом. В этом случае CopyMemory () должна называться таким образом:

CopyMemory(@MyVar, Pointer(Arr), size);

Как вернуть данные из метода2 правильно, не зная, является ли это простым типом (или записи) или массивом? Ситуация будет аналогичной по методу1, но здесь мне пришлось бы использовать

CopyMemory(Pointer(Arr), Pointer(MyVar), size);

В случае массивов и

CopyMemory(Pointer(Arr), @MyVar, size);

В случае простых типов.

Что я могу с этим поделать, когда не знаю, что такое параметр myvar?

Это было полезно?

Решение

Там нет такой вещи, как тип пустоты в Delphi. То, на что вы имеете в виду, называется нетипированный параметр.

Нетипированный параметр всегда Актуальная вещь сама, не указатель на то, что вы должны использовать. Следовательно, правильный способ использования CopyMemory с таким параметром - применить @ оператор для этого, как так:

CopyMemory(@MyVar, @Arr[0], size);

Обратите внимание, что я также изменил способ прохождения второго параметра. Лучше, если вы не полагаетесь на тот факт, что динамический массив действительно является указателем на первый элемент. Если вам нужен указатель на первый элемент, просто скажите так явно, как я здесь.

Ваша путаница исходит из теста, который вы сделали, где использовался параметр, как будто это был указатель, и тест, по -видимому, работал. Я сомневаюсь в обоснованности этого теста. Когда вы сказали Pointer(MyString)^, то, что у вас было, было первым персонажем струны. Когда ты тогда сказал Pointer(MyVar) Внутри функции вы привели к типу этого символа в указатель, который был неверным типом. Если ваша программа, похоже, работала, то это было только случайно; Ваш код был неправильным.

Лучший совет, который я могу дать,-это не типовые вещи, если вам не нужно. И когда вы это сделаете, пожалуйста, убедитесь, что то, что вы набираете тип, действительно имеют такой тип. В вашем случае вам не нужно что-либо печатать, прежде чем вы передаете его как нетипированный параметр. Вы можете позвонить Method1 как это:

Method1(MyString[1], Length(MyString) * Sizeof(Char));

(Я умножаюсь на SizeOf(Char) Так как я не знаю, есть ли у вас Delphi 2009 или нет.)

Кроме того, избегайте нетипированных параметров. Одна из замечательных вещей, которую компилятор может сделать, чтобы помочь обеспечить правильную программу, - это обеспечение безопасности типа, но когда вы убираете типы, компилятор больше не может вам помочь.

Другие советы

Ваша проблема заключается в том, что вы передаете данные или указать на данные методу1/2. Вы всегда должны передавать данные. Может быть, вы просто забыли, что Dynamic Array является самой указателем? Вы не должны передавать или указатель (а) в ваших методах (A - это динамический массив здесь). Передайте [0] или указатель (а)^.

procedure Method1(const MyVar; size: cardinal);
var
  Arr: array of byte;
begin
  SetLength(Arr, size);
  CopyMemory(Pointer(Arr), @MyVar, Size);
end;

procedure Method2(var MyVar; size: cardinal);
var
  Arr: array of byte;
begin
  SetLength(Arr, size);
  Arr[0] := 1;
  Arr[1] := 2;
  Arr[2] := 3;
  Arr[3] := 4;
  CopyMemory(@MyVar, Pointer(Arr), Size);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  I: Integer;
  A: array of Integer;
begin
  I := $01020304;
  Method1(I, 4); // we pass data itself, not the pointer to it.
  Method2(I, 4);
  SetLength(A, 2);
  A[0] := 0;
  A[1] := $01020304;
  Method1(A[0], Length(A) * SizeOf(A[0])); // note, that we pass data, not pointer
  Method2(A[0], Length(A) * SizeOf(A[0])); // A or Pointer(A) is a pointer to array's data
end;

Если А является динамическим массивом:

  1. 0] - это то же самое, что указатель (a)^ и представляет данные массива.
  2. @A [0] - это то же самое, что указатель (A) или просто A и представляет сам массив, что является указателем на его данные (и некоторую техническую информацию о отрицательных смещениях).

Если A - статический массив:

  1. 0] такой же, как и A и представляет сам массив, который является данными массива.
  2. @A [0] это то же самое, что @a, и представляет указатель на массив.
  3. Указатель (а) или указатель (а)^ не имеет смысла.

Обратите внимание, что ARR в методе1/2 также является динамическим массивом, поэтому мы бросаем его на указатель (CopyMemory спрашивает указатели, а не данные). Если мы хотим использовать подпрограмму перемещения (который спрашивает данные), мы должны написать указатель (a)^ вместо этого.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top