Questo sito utilizza cookies, anche di terze parti, per mostrare pubblicità e servizi in linea con il tuo account. Leggi l'informativa sui cookies.
Username: Password: oppure
C# / VB.NET - [C#] Problema con struct e/o classi contenenti array
Forum - C# / VB.NET - [C#] Problema con struct e/o classi contenenti array

Avatar
xeeynamo (Normal User)
Pro


Messaggi: 66
Iscritto: 14/03/2008

Segnala al moderatore
Postato alle 13:00
Sabato, 12/12/2009
Si lo sò, ho rotto un pochetto le scatole con le strutture e con tutte queste operazioni a basso livello col C# XD ma per il lavoro che stò facendo purtroppo mi è obbligatorio usare questi sistemi e il linguaggio più semplice e flessibile per me è il C#.
Passando al problema... Ho una classe/struttura fatta in questo modo:
Codice sorgente - presumibilmente C#

  1. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  2. public class Test
  3. {
  4.     uint var1;
  5.     byte var2;
  6.     ushort var3;
  7.     uint var4;
  8. }


ed eseguendo la funzione
Codice sorgente - presumibilmente Plain Text

  1. Test test;
  2. System.Runtime.InteropServices.Marshal.SizeOf(test);


mi restituisce il valore 11 e sin qui è perfetto perchè posso ordinare classi e strutture come voglio io. Ora voglio metterci all'interno ad esempio un array:

Codice sorgente - presumibilmente C#

  1. public class Test
  2. {
  3.     uint var1;
  4.     byte var2;
  5.     ushort var3;
  6.     uint var4;
  7.     byte[] var5 = new byte[6];
  8. }



ora il valore restituito dovrebb'essere 17, ma mi restituisce 14. Quando vado a copiare dei dati usando le funzioni Marshal nella classe il programma mi restiuisce questa eccezione: AccessViolationException. Ovviamente se tolgo quell'array il programma va liscio come l'olio. Credo che quei 4 bytes che mi genera l'array non sono altro che un puntatore verso una parte di memoria dinamica e quindi non corrispondono al vero array o mi sbaglio? Quindi quando vado a copiare i dati non faccio altro che sostituire il puntatore con dati che non c'entrano niente causando quel tipo di eccezione vero?
Comunque la funzione che uso è questa:

Codice sorgente - presumibilmente C#

  1. public static object Byte2Struct(byte[] buf, object o)
  2.         {
  3.             IntPtr ptPoit = Marshal.AllocHGlobal(buf.Length);
  4.             Marshal.Copy(buf, 0, ptPoit, buf.Length);
  5.             o = Marshal.PtrToStructure(ptPoit, o.GetType());
  6.             Marshal.FreeHGlobal(ptPoit);
  7.             return o;
  8.         }



Come potrei risolvere? :)

Ultima modifica effettuata da xeeynamo il 12/12/2009 alle 13:01
PM Quote
Avatar
Il Totem (Admin)
Guru^2


Messaggi: 3635
Iscritto: 24/01/2006

Segnala al moderatore
Postato alle 21:24
Domenica, 13/12/2009
Dato che gli array sono tipi reference, sì, si tratta di un puntatore. La dimensione, però, è 15 bytes (dato che gli indirizzi sono di 4 bytes, e 11+4=15: ho anche confermato sul mio computer che è esatto).
Non so proprio come risolvere, ma potresti provare ad applicare all'array un attributo del tipo FixedSizeArray. Non mi ricordo di preciso il nome ma se cerchi dovresti trovare qualcosa del genere.


"Infelici sono quelli che hanno tanto cervello da vedere la loro stupidità."
(Fligende Blatter)

"Dubitare di se stessi è il primo segno d'intelligenza."
(Ugo Ojetti)
PM Quote
Avatar
Thejuster (Member)
Guru^2


Messaggi: 1824
Iscritto: 04/05/2008

Segnala al moderatore
Postato alle 9:34
Lunedì, 14/12/2009
Non sò bene se questo potrebbe aiutarti,

hai provato il codice non gestito?

ha appunto la possibilità delle strutture o dei dati di non avere dimensioni fisse.
prova a fare qualche ricerca su google.



Real-time applications, we might need to use pointers to enhance performance in such applications.

External functions, in non-.net DLLs some functions requires a pointer as a parameter, such as Windows APIs that were written in C.

Debugging, sometimes we need to inspect the memory contents for debugging purposes, or you might need to write an application that analyzes another application process and memory.

Performance and flexibility, by using pointer you can access data and manipulate it in the most efficient way possible.
Compatibility, in most cases we still need to use old windows APIs, which use pointers extensively. Or third parties may supply DLLs that some of it’s functions need pointer parameters. Although this can be done by using DLLImport and System.IntPtr class, but in some cases it’s just much simpler to use pointer.
Memory Addresses, there is no way to know the memory address of some data without using pointers.

queste sono una delle tante cose che puoi fare
devi solo leggerti bene la documentazione,
magari scopri se va bene per ciò che vuoi fare o meno
:k:


Ultima modifica effettuata da Thejuster il 14/12/2009 alle 9:49


PM Quote
Avatar
Il Totem (Admin)
Guru^2


Messaggi: 3635
Iscritto: 24/01/2006

Segnala al moderatore
Postato alle 16:09
Lunedì, 14/12/2009
Ma... cosa c'entra?
Lui voleva solo convertire un array di bytes in una variabile strutturata usando l'allocazione della memoria e il namespace Marshal (che offre supporti managed per risorse non gestite). Il problema è che gli oggetti vengono rappresentati come puntatori e non con il loro contenuto, nella fattispecie l'array è un puntatore al primo byte e non un array di bytes.


"Infelici sono quelli che hanno tanto cervello da vedere la loro stupidità."
(Fligende Blatter)

"Dubitare di se stessi è il primo segno d'intelligenza."
(Ugo Ojetti)
PM Quote
Avatar
Thejuster (Member)
Guru^2


Messaggi: 1824
Iscritto: 04/05/2008

Segnala al moderatore
Postato alle 18:06
Lunedì, 14/12/2009
ah ecco.
chiedo scusa allora
avevo inteso io male cosa voleva fare 8-|


PM Quote
Avatar
xeeynamo (Normal User)
Pro


Messaggi: 66
Iscritto: 14/03/2008

Segnala al moderatore
Postato alle 22:10
Lunedì, 14/12/2009
Ho trovato una soluzione temporanea... Ho fatto il codice così:
Codice sorgente - presumibilmente C#

  1. internal byte[] savemap;
  2.  
  3.         private ushort Get16(int offset){
  4.             return (ushort)(savemap[offset] + (savemap[offset + 1] << 8));
  5.         }
  6.         private void Set16(int offset, ushort value)
  7.         {
  8.             savemap[offset + 0] = (byte)(value >> 8 & 0xFF);
  9.             savemap[offset + 1] = (byte)(value & 0xFF);
  10.         }
  11.         private uint Get32(int offset)
  12.         {
  13.             return (uint)(savemap[offset] + (savemap[offset + 1] << 8) + (savemap[offset + 2] << 16) + (savemap[offset + 3] << 24));
  14.         }
  15.         private void Set32(int offset, uint value)
  16.         {
  17.             savemap[offset + 0] = (byte)(value >> 24 & 0xFF);
  18.             savemap[offset + 1] = (byte)(value >> 16 & 0xFF);
  19.             savemap[offset + 2] = (byte)(value >> 8 & 0xFF);
  20.             savemap[offset + 3] = (byte)(value & 0xFF);
  21.         }
  22.         private byte[] GetB(int offset, int size)
  23.         {
  24.             byte[] ret = new byte[size];
  25.             for (int i = 0; i < size; i++)
  26.                 ret[i] = savemap[offset + i];
  27.             return ret;
  28.         }
  29.         private void SetB(int offset, byte[] value)
  30.         {
  31.             for (int i = 0; i < value.Length; i++)
  32.                 savemap[offset + i] = value[i];
  33.         }
  34.  
  35.         public uint Checksum { get { return Get32(0x0000); } set { Set32(0x0000, value); } }
  36.         public byte PreviewCharacterLeadLevel { get { return savemap[0x0004]; } set { savemap[0x0004] = value; } }
  37.         public byte PreviewCharacterLeadPortrait { get { return savemap[0x0005]; } set { savemap[0x0004] = value; } }
  38.         public byte PreviewCharacterSecondPortrait { get { return savemap[0x0006]; } set { savemap[0x0005] = value; } }
  39.         public byte PreviewCharacterThirdPortrait { get { return savemap[0x0007]; } set { savemap[0x0006] = value; } }



e così via :D l'unica cosa è che sarà scocciante fare tutti quei get e set, dato che il byte sarà grande 2048 bytes :S

PM Quote
Avatar
Il Totem (Admin)
Guru^2


Messaggi: 3635
Iscritto: 24/01/2006

Segnala al moderatore
Postato alle 17:26
Martedì, 15/12/2009
Basta usare un for, ad esempio:
Codice sorgente - presumibilmente C# / VB.NET

  1. private void Set32(int offset, uint value)
  2. {
  3.   for(int i = 0; i < 4; i++)
  4.     savemap[offset + i] = (byte)(value >> (8 * (3 - i)));
  5. }


Non capisco perchè fai & 0xFF, che x & 1 restituisce 1 solo se x è 1 e 0 altrimenti, ossia se x è 0. Quindi x & 1 = x e perciò n & 0xFF = n.

In generale:
Codice sorgente - presumibilmente C# / VB.NET

  1. private void SetInteger(int offset, UInt64 value, byte bits)
  2. {
  3.   for(int i = 0; i < (int)(bits / 8); i++)
  4.     savemap[offset + i] = (byte)(value >> (8 * ((bits / 8) - 1 - i)));
  5. }


Ultima modifica effettuata da Il Totem il 15/12/2009 alle 17:27


"Infelici sono quelli che hanno tanto cervello da vedere la loro stupidità."
(Fligende Blatter)

"Dubitare di se stessi è il primo segno d'intelligenza."
(Ugo Ojetti)
PM Quote
Avatar
xeeynamo (Normal User)
Pro


Messaggi: 66
Iscritto: 14/03/2008

Segnala al moderatore
Postato alle 20:05
Martedì, 15/12/2009
Testo quotato

Postato originariamente da Il Totem:

Basta usare un for, ad esempio:
Codice sorgente - presumibilmente C# / VB.NET

  1. private void Set32(int offset, uint value)
  2. {
  3.   for(int i = 0; i < 4; i++)
  4.     savemap[offset + i] = (byte)(value >> (8 * (3 - i)));
  5. }


Non capisco perchè fai & 0xFF, che x & 1 restituisce 1 solo se x è 1 e 0 altrimenti, ossia se x è 0. Quindi x & 1 = x e perciò n & 0xFF = n.

In generale:
Codice sorgente - presumibilmente C# / VB.NET

  1. private void SetInteger(int offset, UInt64 value, byte bits)
  2. {
  3.   for(int i = 0; i < (int)(bits / 8); i++)
  4.     savemap[offset + i] = (byte)(value >> (8 * ((bits / 8) - 1 - i)));
  5. }




L'ho fatto perchè se ad esempio del numero  N = 0x12345678 avrei voluto prendere solo 0x34, avrei dovuto fare N << 16 e sarebbe rimasto  0x1234, poi facevo N & 0xFF e mi usciva 0x34

PM Quote
Avatar
Il Totem (Admin)
Guru^2


Messaggi: 3635
Iscritto: 24/01/2006

Segnala al moderatore
Postato alle 18:17
Mercoledì, 16/12/2009
Ah giusto...


"Infelici sono quelli che hanno tanto cervello da vedere la loro stupidità."
(Fligende Blatter)

"Dubitare di se stessi è il primo segno d'intelligenza."
(Ugo Ojetti)
PM Quote