Hint: C arrays are passed by reference

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Mathias
Beiträge: 6710
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Hint: C arrays are passed by reference

Beitrag von Mathias »

In C habe ich folgende Anbindung in der *.h

Code: Alles auswählen

extern void test(guint8 oarr[64]);
Wie setze ich die korrekt in Pascal um ?
Es Funktionieren beide Varianten.
Nur bei der ersten Variante bekomme ich den Hinweis. "Hint: C arrays are passed by reference";

Variante 2 hätte den Vorteil, das ich die Typendeklaration sparen kann.
Dafür hat es keine Typenprüfung und man kann alles mögliche übergeben.

Code: Alles auswählen

type
  Tint8Arr = array[0..63] of uint8;

var
  zigzag_matrix: Tint8Arr;
  raster_matrix: Tint8Arr;

// extern void test(guint8 oarr[64]);

  procedure test1(arr: Tint8Arr); cdecl; external 'foo';
  procedure test2(arr: PInt8); cdecl; external 'foo';

begin
  test1(raster_matrix, zigzag_matrix);
  test2(@raster_matrix, @zigzag_matrix);
end.
h2pas übersetzt es folgendermassen, was sich natürlich nicht kompilieren lösst.

Code: Alles auswählen

procedure test(oarr:array[0..63] of Tguint8);cdecl;external;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot


PascalDragon
Beiträge: 904
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Hint: C arrays are passed by reference

Beitrag von PascalDragon »

Mathias hat geschrieben: Do 28. Nov 2024, 19:46 Nur bei der ersten Variante bekomme ich den Hinweis. "Hint: C arrays are passed by reference";
Du kannst den Parameter einfach als var deklarieren. Das entspricht dann auch eher dem was C macht.
FPC Compiler Entwickler

Mathias
Beiträge: 6710
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Hint: C arrays are passed by reference

Beitrag von Mathias »

Du kannst den Parameter einfach als var deklarieren. Das entspricht dann auch eher dem was C macht.
Da verschwindet zwar die Warnung, aber dafür bleibt er stecken sobald man sowas übergeben will.

Code: Alles auswählen

{$j-}
const
  zigzag_matrix: Tguint8arr64 = (
    8, 16, 19, 22, 26, 27, 29, 34, .....
Da war mir nahelegend "var" durch "const* zu ersetzen. Aber dao kommt die Warnung wieder.

So habe ich es auch probiert. Da kommt keine Warnung mehr, auch funktioniert es.
Aber dafür habe ich keine Typenprüfung mehr und man kann jeden Mist mitgeben.

Code: Alles auswählen

 procedure test2(var o; const i); cdecl; external 'foo';
Ich habe es gerade nochmals in C probiert.

Code: Alles auswählen

extern void test(guint8 oarr[64])
...
guint i1 [10];   // gibt eine Warnung aus
test(i1);
guint i1 [100]; // Wir anstandslos übernommen
test(i1);
int i3; // // gibt eine Warnung aus
test(i3);
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Mathias
Beiträge: 6710
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Hint: C arrays are passed by reference

Beitrag von Mathias »

Jetzt sehe ich den Sinn von dieser Variante, obwohl sie keine Typenprüfung hat.

Code: Alles auswählen

procedure test2(var o; const i); cdecl; external 'foo';
C-Seitig kann man es auch so aufrufen, solange es kein Überlauf gibt, kommt auch keine Warnung.

Code: Alles auswählen

guint8 arr1[1000];
guint8 arr2[64];
test(&arrr1[ofs], arr2);
ZB. Bei einer 4x4 Matrix kann man eine "array [0..15] of byte" oder "array [0..3, 0..3] of byte" nehmen.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

PascalDragon
Beiträge: 904
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Hint: C arrays are passed by reference

Beitrag von PascalDragon »

Ich zumindest meinte einfach ein var vor den Parameter zu setzen:

Code: Alles auswählen

procedure test1(var arr: Tint8Arr); cdecl; external 'foo';
FPC Compiler Entwickler

Mathias
Beiträge: 6710
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Hint: C arrays are passed by reference

Beitrag von Mathias »

Ich zumindest meinte einfach ein var vor den Parameter zu setzen:
Nur wie schon gesagt, funktioniert dies nicht mit echten Konstanten. Weil wen man "const" anstelle "var" nimmt, kommt wieder eine Warnung.

Ich denke, ich werde bei dieser Variante bleiben.

Code: Alles auswählen

procedure test2(var o; const i); cdecl; external 'foo';
Man hat zwar keine Typenprüfung, dafür ist die Warnung weg und man hat die gleiche Flexibilität wie bei C.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Mathias
Beiträge: 6710
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Hint: C arrays are passed by reference

Beitrag von Mathias »

Das übergeben einer Array konnte ich wie oben beschrieben lösen.

Aber wie sieht es bei einer Function aus, wen eine Array zurück kommt.

Code: Alles auswählen

typedef struct {
  float x, y, z, w;
} v4;

extern v4 v_add(const v4 a, const v4 b);
Einer eine Idee, wie man dies lösen könnte.

Ich habe es auf diese Art probiert, aber es kommt nur 0,0,0,0 zurück.

Code: Alles auswählen

type
  v4 = record
    x, y, z, w: Single;
  end;

function v_add(const a, b: v4): v4; cdecl; external;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

PascalDragon
Beiträge: 904
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Hint: C arrays are passed by reference

Beitrag von PascalDragon »

Mathias hat geschrieben: Mo 23. Dez 2024, 15:45 Aber wie sieht es bei einer Function aus, wen eine Array zurück kommt.
Ich nehme an du meinst struct/record? 🤔
Mathias hat geschrieben: Mo 23. Dez 2024, 15:45 Einer eine Idee, wie man dies lösen könnte.
Ich kann es nicht nachvollziehen (Plattform: x86_64-linux):

structret.c

Code: Alles auswählen

typedef struct
{
        float x, y, z, w;
} v4;

v4 v_add(const v4 a, const v4 b)
{
        v4 ret;
        ret.x = a.x + b.x;
        ret.y = a.y + b.y;
        ret.z = a.z + b.z;
        ret.w = a.w + b.w;
        return ret;
}
tstructret.pp

Code: Alles auswählen

program tstructret;

{$L structret.o}

type
  v4 = record
    x, y, z, w: Single;
  end;

function AddPas(const a, b: v4): v4;
begin
  AddPas.x := a.x + b.x;
  AddPas.y := a.y + b.y;
  AddPas.z := a.z + b.z;
  AddPas.w := a.w + b.w;
end;

function AddC(const a, b: v4): v4; cdecl; external name 'v_add';

var
  a, b, c: v4;
begin
  a.x := 1;
  a.y := 2;
  a.z := 3;
  a.w := 4;
  b.x := 30;
  b.y := 40;
  b.z := 50;
  b.w := 60;

  c := AddPas(a, b);
  Writeln(c.x, ' ', c.y, ' ', c.z, ' ', c.w);
  c := Default(v4);
  c := AddC(a, b);
  Writeln(c.x, ' ', c.y, ' ', c.z, ' ', c.w);
end.
Ausgabe

Code: Alles auswählen

 3.100000000E+01  4.200000000E+01  5.300000000E+01  6.400000000E+01
 3.100000000E+01  4.200000000E+01  5.300000000E+01  6.400000000E+01
FPC Compiler Entwickler

Mathias
Beiträge: 6710
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Hint: C arrays are passed by reference

Beitrag von Mathias »

Ich habe nun mein Programm mal minimiert.

Code: Alles auswählen

program project1;

const
  libgraphene = 'libgraphene-1.0';

type
  Tgraphene_simd4f_t = record
    x, y, z, w: single;
  end;

  function graphene_simd4f_init(x: single; y: single; z: single; w: single): Tgraphene_simd4f_t; cdecl; external libgraphene;

  function graphene_simd4f_get_x(s: Tgraphene_simd4f_t): single; cdecl; external libgraphene;
  function graphene_simd4f_get_y(s: Tgraphene_simd4f_t): single; cdecl; external libgraphene;
  function graphene_simd4f_get_z(s: Tgraphene_simd4f_t): single; cdecl; external libgraphene;
  function graphene_simd4f_get_w(s: Tgraphene_simd4f_t): single; cdecl; external libgraphene;

var
  res: Tgraphene_simd4f_t;
  x, y, z, w: single;

begin
  res := graphene_simd4f_init(1.1, 2.2, 3.3, 4.4);

  WriteLn('size: ', SizeOf(res));

  x := graphene_simd4f_get_x(res);
  y := graphene_simd4f_get_y(res);
  z := graphene_simd4f_get_z(res);
  w := graphene_simd4f_get_w(res);

  WriteLn('x: ', x: 4: 2, '  y: ', y: 4: 2, '  z: ', z: 4: 2, '  w: ', w: 4: 2);
end.  
Ausgabe:

Code: Alles auswählen

size: 16
x: 1.10  y: 2.20  z: 0.00  w: 0.00
Mache ich das ganze in einem C-Programm, kommen alle 4 Werte richtig.
Das sizeof ist zum test, ob an beiden Orten der record/struct 16Byte gross ist.

In C ist der struct so deklariert:

Code: Alles auswählen

# if defined(GRAPHENE_USE_SSE)
#  include <xmmintrin.h>
#  include <emmintrin.h>
#  if defined(_M_IX86_FP)
#   if _M_IX86_FP >= 2
#    define GRAPHENE_USE_SSE4_1
#   endif
#  elif defined(__SSE4_1__)
#   define GRAPHENE_USE_SSE4_1
#  elif defined(_MSC_VER)
#   define GRAPHENE_USE_SSE4_1
#  endif
#  if defined(GRAPHENE_USE_SSE4_1)
#   include <smmintrin.h>
#  endif
typedef __m128 graphene_simd4f_t;
# elif defined(GRAPHENE_USE_ARM_NEON)
#  if defined (_MSC_VER) && (_MSC_VER < 1920) && defined (_M_ARM64)
#   include <arm64_neon.h>
#  else
#   include <arm_neon.h>
#  endif
typedef float32x4_t graphene_simd4f_t;
# elif defined(GRAPHENE_USE_GCC)
typedef float graphene_simd4f_t __attribute__((vector_size(16)));
# elif defined(GRAPHENE_USE_SCALAR)
typedef struct {
  /*< private >*/
  float x, y, z, w;
} graphene_simd4f_t;
# else
#  error "Unsupported platform."
# endif
Diese Zeile ist in codeblock schwarz, somit ist dies die richtige Deklaration.

Code: Alles auswählen

typedef float graphene_simd4f_t __attribute__((vector_size(16)));
Alles andere ist grau.

Wen das ganze etwas mit SEE zu tun hätte, müsste dann bei sizeof nicht was anderes als 16 kommen ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten