Forum: PC-Programmierung C# ads Twincat Strukturen


von Peter (Gast)


Lesenswert?

Also habe folgendes Problem.

Sobald ich diese Struktur als Array machen will, kommt immer ein Fehler
1
        public unterstruktur[] unterstruc = new unterstruktur[4];
Wenn ich diese Struktur einfach 4 mal untereinander kopiere und 
deklariere funktioniert es. Wieso nicht mit Array? (Wenn ich die 
SizeConst auf 45 setzte kommt folgender Fehler: 
FatalExecutionEngineError
1
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
2
    public class unterstruktur
3
    {
4
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
5
        public int[] dintArr = new int[4];
6
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)]
7
        public string stringVal = "";
8
    }
9
10
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
11
    public class GlobalTestType
12
    {
13
        public short intVal;
14
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
15
        public int[] dintArr = new int[4];
16
        [MarshalAs(UnmanagedType.I1)]
17
        public bool boolVal;
18
        public byte byteVal;
19
        public float floatVal;
20
        public double doubleVal;
21
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)]
22
        public string stringVal = "";
23
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
24
        public unterstruktur[] unterstruc = new unterstruktur[4];
25
    }

von Peter (Gast)


Lesenswert?

Bzw die Fehlermeldung: Der Objektverweis wurde nicht auf eine 
Objektinstanz festgelegt.

von Peter II (Gast)


Lesenswert?

ich glaube es liegt daran das du gleichzeitig eine initalisierung und 
eine Deklaration machst.

> public unterstruktur[] unterstruc = new unterstruktur[4];

http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/cb0e396f-1461-4222-9877-9e1d3eea9875/

ich würde sagen das new ... ist der fehler, es darf kein = in der 
stuctur vorkommen.

von Markus V. (valvestino)


Lesenswert?

Hallo Peter,

diese Codezeile
1
public unterstruktur[] unterstruc = new unterstruktur[4];
allokiert erst einmal nur den Speicher für das Array mit den 
unterstruktur-Referenzen. Das ist entfernt damit vergleichbar, dass erst 
einmal nur Speicher für sowas wie Pointer allokiert wird. Was noch fehlt 
ist folgendes:
1
for (int index=0; index<4; index++)
2
{
3
    unterstruc[index] = new unterstruktur();
4
}
ABER: Damit ist überhaupt nicht gewährleistet, dass die einzelnen 
unterstruktur-Objekte direkt hintereinander im Speicher liegen, da die 
Runtime die einzelnen Objekte irgendwo im Speicher anlegen kann.

Gruß
Markus

von Markus V. (valvestino)


Lesenswert?

Was ich noch ergänzen wollte:
DotNet unterscheidet zwischen Referenz-Typen und Value-Typen. Bei 
Referenztypen wird durch die Deklaration einer Variablen lediglich die 
Referenz (eine Art "Pointer") auf das Objekt im Speicher angelegt. Diese 
Referenz kann null sein, also irgendwo ins Nirvana verweisen. Klassen 
(auch die Klasse System.String!) sind IMMER Referenztypen. Im Gegensatz 
dazu wird bei den Valuetypen Speicher für den "Wert" der Variable (ohne 
Indirektion durch eine Referenz) angelegt. Referenztypen sind z.B. int, 
double, also alle skalaren Typen. Aber auch struct-Typen sind 
Value-Typen. Dazu zählen z.B. die (vermeintlichen) "Klassen" 
System.DateTime, System.Guid, ... oder eben selbst definierte 
Struct-Typen. Solche Value-Typen können auch niemals "null" sein.

Wenn Du also anstelle von "class unterstruktur" "struct unterstruktur" 
schreibst, allokierst du mit new unterstruktur[4] 4 unterstruktur 
Elemente und deren Speicher, an einem Stück.

Auch hier ein ABER: Deine "unterstruktur" enthält ein Feld vom Typ 
string. Wie ich oben erwähnt habe, string ist wiederum ein Referenz-Typ. 
Deine unterstruktur enthält anstelle des tatsächloiczhen Strings "nur" 
einen Verweis auf das tatsächliche String-Objekt und nicht etwas 
irgendwelchen Speicher für String-Inhalte.

Hier gibt es noch einen (englischen) Artikel, der das Thema etwas näher 
erläutert: 
http://www.codeproject.com/Articles/76153/Six-important-NET-concepts-Stack-heap-value-types

Gruß
Markus

von Peter (Gast)


Lesenswert?

Weil ich weiß das bei die daten vom Twincatarray 0 in unterstruc  und 
von 1 in unterstruc1  stehen.
1
    public unterstruktur unterstruc = new unterstruktur();
2
    public unterstruktur unterstruc1 = new unterstruktur();

aber auch die for initialisierung funktioniert nicht. es wird ja auch 
kein fehler bei der initialisierung angezeigt...

von Markus V. (valvestino)


Lesenswert?

Peter schrieb:
> aber auch die for initialisierung funktioniert nicht. es wird ja auch
> kein fehler bei der initialisierung angezeigt...

Habe ich ja schon in meinem ersten Post geschrieben. Siehe Abschnitt 
nach ABER.

Gruß
Markus

von Arc N. (arc)


Lesenswert?

Markus Volz schrieb:
> ABER: Damit ist überhaupt nicht gewährleistet, dass die einzelnen
> unterstruktur-Objekte direkt hintereinander im Speicher liegen, da die
> Runtime die einzelnen Objekte irgendwo im Speicher anlegen kann.

Einfach mal ausprobieren...
1
// C/C++ in einer nativen Win32-DLL
2
#pragma pack(4)
3
struct SubStruct {
4
  double a;
5
  float b;
6
};
7
#pragma pack(4)
8
struct TestStruct {
9
  int c;
10
  unsigned char d;
11
  SubStruct e[4];
12
};
13
14
extern "C" {
15
  WIN32PROJECT1_API double _cdecl fnWin32Project1(TestStruct* tp)
16
  {
17
    return tp->e[2].a;
18
  }
19
}
20
21
und in C#
22
23
    [StructLayout(LayoutKind.Sequential, Pack = 4)]
24
    public struct SubStruct {
25
      public double a;
26
        public float b;
27
    };
28
29
    [StructLayout(LayoutKind.Sequential, Pack = 4)]
30
    public struct TestStruct {
31
        public int c;
32
        public byte d;
33
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
34
        public SubStruct[] e;
35
    };
36
37
        [DllImport(@"Win32Project1.dll", EntryPoint = "fnWin32Project1", CallingConvention = CallingConvention.Cdecl)]
38
        public static extern double fnWin32Project1(ref TestStruct tp);
39
40
        void TestCall() {     
41
            TestStruct ac = new TestStruct();
42
            ac.e = new SubStruct[4];
43
            ac.e[2].a = 12345.6;
44
            double res = fnWin32Project1(ref ac);
45
            return res;
46
        }

von Markus V. (Gast)


Lesenswert?

@Arc Net
Arc Net schrieb:
>> ABER: Damit ist überhaupt nicht gewährleistet, dass die einzelnen
>> unterstruktur-Objekte direkt hintereinander im Speicher liegen, da die
>> Runtime die einzelnen Objekte irgendwo im Speicher anlegen kann.
Wenn Du meine ersten beiden Posts etwas genauer gelesen hättest ;-), 
wäre Dir wahrscheinlich aufgefallen, dass das von Dir zitierte ABER sich 
auf Klassen (class) bezieht. Dein Beispiel verwendet struct. Dazu habe 
ich in meinem 2. Post was geschrieben. :-)

Gruß
Markus

von Markus V. (Gast)


Lesenswert?

@Arc Net
Sorry, man muß natürlich AUCH den Post der TOs aufmerksam lesen.
Peter schrieb:
> public class unterstruktur

Grüße
Markus

von Arc N. (arc)


Lesenswert?

Markus V. schrieb:
> @Arc Net
> Sorry, man muß natürlich AUCH den Post der TOs aufmerksam lesen.

Ja, sollte man tun...

> Dein Beispiel verwendet struct. Dazu habe ich in meinem 2. Post was
> geschrieben. :-)

Das hätte auch nicht überlesen werden sollen...
(bin froh das die nächsten vier Tage frei sind)

von Peter (Gast)


Lesenswert?

Hallo nochmal

sorry habe jetzt einiges ausprobiert. Auch z.b. ein Bytearray anzulegen 
wo ich den String dann probieren würde auszulesen. (als struct nicht als 
class). Welche möglichkeiten gäbe es denn auf dieses stukturarray 
zuzugreifen?

von Peter (Gast)


Lesenswert?

Hallo?

Gibt es nicht irgendwie die möglichkeit einen String aus einem 
Strukturarray auszulesen?

von Markus V. (Gast)


Lesenswert?

Klar gibts da was. Schau Dir mal die Klasse System.Text.ASCIIEncoding 
an. 
http://msdn.microsoft.com/en-us/library/system.text.asciiencoding.aspx

Neben ASCIIEncoding gibt es im Namespace auch noch UnicodeEncoding, 
UTF32Encoding, UTF7Encoding und UTF8Encoding. Wie die Klassen verwendet 
werden, findest Du in einem Beispiel unter dem obigen Link.

Gruß
Markus

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.