Usafe struct - 1.lekce – .NET – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Usafe struct - 1.lekce – .NET – Fórum – Programujte.comUsafe struct - 1.lekce – .NET – Fórum – Programujte.com

 

Toto vlákno bylo označeno za vyřešené — příspěvek s řešením.
BDS+3
Věrný člen
12. 8. 2015   #1
-
0
-

Ahoj, zkouším si použití "unsafe struct" pro ukládání strukturovaných dat.

Co mám v tomto kódu špatně:

using System;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;

namespace StructTest1
{
    class Program
    {
        static void Main(string[] args)
        {
            unsafe
            {
               TestData buf;

                for (int i = 0; i < 6; i++) buf.head[i] = 0xFA;
                buf.dataA[0] = 'A';
                buf.dataA[1] = ':';
                buf.dataB[0] = 'B';
                buf.dataB[1] = ':';

                // výstupní soubor vypadá takto:
                // FA00 0000 0000 4100 0000 0000 4200 0000 0000

                // očekával bych tento formát:
                // FAFA FAFA FAFA 4100 3A00 0000 4200 3A00 0000

                FileStream fs;
                try
                {
                    fs = new FileStream("vystup", FileMode.Create);
                    BinaryWriter w;
                    try
                    {

                        w = new BinaryWriter(fs, Encoding.Unicode);
                        int cnt = 0;
                        byte[] out_buf = getBytes(buf, out cnt);
                        w.Write(out_buf, 0, cnt);
                        w.Close();
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("Chyba pri zapisu!");
                    }
                    finally
                    {
                        fs.Close();
                    }
                }
                catch (Exception)
                {
                    Console.WriteLine("Do souboru nelze zapisovat!");
                }

                Console.WriteLine("stiskni enter pro ukonceni..\n");
                Console.ReadKey();
            }

        }

        private static byte[] getBytes(TestData str, out int count)
        {
            count = Marshal.SizeOf(str);
            byte[] arr = new byte[count];

            IntPtr ptr = Marshal.AllocHGlobal(count);
            Marshal.StructureToPtr(str, ptr, true);
            Marshal.Copy(ptr, arr, 0, count);
            Marshal.FreeHGlobal(ptr);
            return arr;
        }
    }
    //-----------------------------------------------------------
    internal unsafe struct TestData
    {
        public fixed byte  head[6];
        public fixed char dataA[3];
        public fixed char dataB[3];
    }
}

?

(Popis problému je v komentáři).

Nahlásit jako SPAM
IP: 185.69.69.–
W11 :)
Kit+15
Guru
12. 8. 2015   #2
-
0
-

#1 BDS
Zajímavé. Mně to vypisuje ještě jinak: 

// fafa fafa fafa 0941 0000 0000 0042 0000 0018

Kompilátor mcs.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:207:e...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
Matěj Andrle+1
Grafoman
14. 8. 2015   #3
-
0
-

#1 BDS
Endianita, bitová konvence, ...

Nahlásit jako SPAM
IP: 90.182.189.–
Kit+15
Guru
14. 8. 2015   #4
-
0
-

#3 Matěj Andrle
Proto je to také "unsafe". Vývojář si v tu chvíli musí uvědomit, že výstup může být závislý na platformě a může to zcela znehodnotit kvalitu jeho aplikace.

Když se na ten program koukám, tak to "unsafe" vidím jako zbytečné. Celé by se to dalo podstatně zkrátit.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:207:e...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
BDS+3
Věrný člen
14. 8. 2015   #5
-
0
-

#4 Kit
nedělám žádný kompletní software, tento program dělám je v rámci "výuky".

Jestli někdo víte jak, jak se dá vytvořit program na uložení "unsafe struct" do souboru, tak prosím poraďte.

V uvedené příkladu se mi jedná o funkci "byte[] getBytes" - ta nepracuje správně.

Nahlásit jako SPAM
IP: 94.113.253.–
W11 :)
Matěj Andrle+1
Grafoman
14. 8. 2015   #6
-
0
-

#5 BDS
Serializace...

Nahlásit jako SPAM
IP: 90.182.189.–
Kit+15
Guru
14. 8. 2015   #7
-
0
-

#5 BDS
Poradím, ale potřebuji k tomu vědět, co jsou data a co jsou povinné položky cílového datového formátu. Je to v jedné hromadě a není to příliš přehledné.

Rada č. 1: Místo "try .. catch" zkus použít "using".

Rada č: 2: Místo getBytes by se spíš hodilo něco jako write(BinaryWriter, String), která ty vyrobené bajty rovnou zapíše do "w". Kromě toho to pole "arr" uvnitř getBytes máš moc malé. Proč ho vůbec vytváříš?

Rada č. 3: Uniká mi význam proměnné "ptr". Vývojáři přešli od C++ k C# právě proto, aby se těchto konstrukcí zbavili. Zkus to nahradit něčím elegantnějším.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:207:e...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
BDS+3
Věrný člen
14. 8. 2015   #8
-
0
-

Řekněme, že mám soubor který obsahuje 100 000 položek (v c++ uložených struktur o pevné velikosti) ve formátu:

{

char vlastnostA [32];

char vlastnostB [16];

char vlastnostC [16];

char vlastnostD [8];

char vlastnostE [8];

double hodnotaA;

long hodnotaB;

int hodnotaC;

short pole1[12];

byte pole2[256];

};

já budu muset zachovat tento formát (z důvodu kompatibility).

Jak data do souboru ukládat a připisovat bez toho, abych musel přepisovat celý soubor a nemusel data zapisovat po jedné položce. A samozřejmě pak data číst.

Nahlásit jako SPAM
IP: 94.113.253.–
W11 :)
BDS+3
Věrný člen
14. 8. 2015   #9
-
0
-

#7 Kit
Rada č. 3

ta funkce se uvádí na netu na několika diskuzích, jen jsem ji zkopíroval, její obsah zatím nechápu.

Nahlásit jako SPAM
IP: 94.113.253.–
W11 :)
BDS+3
Věrný člen
14. 8. 2015   #10
-
0
-

#3 Matěj Andrle
Endialita - to by snad bylo jen prohozené. Ne?

Nahlásit jako SPAM
IP: 94.113.253.–
W11 :)
Matěj Andrle+1
Grafoman
14. 8. 2015   #11
-
0
-

#8 BDS
A v jakém formátu je to uloženo - zdrojový kód? Serializace? Kompilace? ...

Nahlásit jako SPAM
IP: 90.182.189.–
BDS+3
Věrný člen
14. 8. 2015   #12
-
0
-

#11 Matěj Andrle

je to uloženo klasicky, binárně

kod mohl vypadat takto:

#include <stdio.h>

struct ITEMDATA
{
char vlastnostA [32];
char vlastnostB [16];
char vlastnostC [16];
char vlastnostD [8];
char vlastnostE [8];
double hodnotaA;
long hodnotaB;
int hodnotaC;
short pole1[12];
byte pole2[256];
};

ITEMDATA library[100000];

...
FILE *fi = fopen(".......
...
fwrite(library, sizeof(ITEMDATA), 100000, fi);

Nahlásit jako SPAM
IP: 94.113.253.–
W11 :)
Řešení
p3can
~ Anonymní uživatel
312 příspěvků
14. 8. 2015   #13
-
0
-
Vyřešeno Nejlepší odpověď

#1 BDS

fixed arrays je zabugovane. doporucuju pouzivat normalni pole s attributem o konstantni delce.

    [StructLayout(LayoutKind.Sequential)]
    internal class TestData
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
        public byte[] head;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public char[] dataA;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public char[] dataB;
        public TestData()
        {
            head = new byte[6];
            dataA = new char[3];
            dataB = new char[3];
        }
    }
Nahlásit jako SPAM
IP: 77.92.213.–
Kit+15
Guru
14. 8. 2015   #14
-
0
-

#8 BDS
To už by bylo lepší ta data zkonvertovat do databáze a pak už jen pracovat s databází. Úplně se tak vyhneš těmto strojovým závislostem, aplikace se tím významně zjednoduší. V případě potřeby můžeš zase udělat export.

Jako docela zásadní chybu vidím nicneříkající označení sloupců "head", "dataA" a "dataB". Chápu, že to chceš udělat univerzálně, ale používání bezvýznamných názvů proměnných vede do binárních pekel.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:207:e...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
BDS+3
Věrný člen
14. 8. 2015   #15
-
0
-

#14 Kit

To už by bylo lepší ta data zkonvertovat do databáze a pak už jen pracovat s databází. Úplně se tak vyhneš těmto strojovým závislostem, aplikace se tím významně zjednoduší. V případě potřeby můžeš zase udělat export.

V případě, že je nutnost zachovat formát souboru, aby byl čitelný pro jiné aplikace, tak přece nic jiného nezbude... A dělat import a export - co by se tím změnilo?

Jako docela zásadní chybu vidím nicneříkající označení sloupců "head", "dataA" a "dataB". Chápu, že to chceš udělat univerzálně, ale používání bezvýznamných názvů proměnných vede do binárních pekel.

Tato struktura je ukázková, pouze pro téma diskuze. Do kódu samozřejmě uvádím hodnoty tak, abych se i po čase ve zdrojáku vyznal...

Nahlásit jako SPAM
IP: 185.69.69.–
W11 :)
BDS+3
Věrný člen
14. 8. 2015   #16
-
0
-

#13 p3can
Díky moc, takto to funguje.

Ale přesto, budu rád, pokud mi kážete nějaká další řešení pro C# .NET - "jak ukládat struktury či třídy do souboru o pevně dané velikosti."

Nahlásit jako SPAM
IP: 185.69.69.–
W11 :)
Kit+15
Guru
14. 8. 2015   #17
-
0
-

#15 BDS
Vkládání či mazání záznamů v obyčejném souboru je dost opruz, zejména pokud je na sdíleném úložišti - dřív nebo později o ta data přijdeš. Databáze bývají proti takovým chybám jištěny.

Takže sem dáváš takové názvy proměnných, abychom se v tom nevyznali...

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:a4f5:...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
BDS+3
Věrný člen
14. 8. 2015   #18
-
0
-

#17 Kit
Takže sem dáváš takové názvy proměnných, abychom se v tom nevyznali...

omlouvám se, netušil jsem, že název proměnné je pro tento dotaz podstatný.

Nahlásit jako SPAM
IP: 185.69.69.–
W11 :)
Kit+15
Guru
14. 8. 2015   #19
-
0
-

#18 BDS
Strukturované programování je založeno na správném používání syntaxe. Při objektovém programování je kladen mnohem větší důraz na sémantiku. Názvy proměnných jsou součástí sémantiky. Chybně nazvanou proměnnou často poznáš podle toho, že je okomentována.

Pochybuji, že proměnné fs, w, buf, arr a out_buf máš v ostré verzi pojmenované jinak. Neoficiální zkratky se v názvech proměnných nepoužívají.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:a4f5:...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
BDS+3
Věrný člen
14. 8. 2015   #20
-
0
-

#19 Kit
Jo máš pravdu, toto je pouze testovací kód, u takových to neřeším vůbec.

A jinak pokud funkce obsahuje pouze jeden interní FileStream dám mu vždy název fs, stejně tak BinaryWriter vždy pojmenuji w. (nikdy nic jiného nepojmenuji fs, nebo w, a nikdy např. fs nepoužiji do parametru funkce).

"Neoficiální zkratky se v názvech proměnných nepoužívají"

Jaké jsou ty oficiální?

Nahlásit jako SPAM
IP: 185.69.69.–
W11 :)
Kit+15
Guru
14. 8. 2015   #21
-
0
-

#20 BDS
Chápu. fs, w, i, j, k, apod. jsou takové lokální názvy, které se používají všude, kde je to možné.

Na druhou stranu: Proč bys fs nepoužil do parametru funkce, kdyby ten parametr byl typu FileStream?

Oficiálních zkratek je hodně a běžně se s nimi setkáváme i v civilním životě. Asi těžko pojmenuješ proměnnou daňZPřidanéHodnoty. Místo toho použiješ běžnou zkratku dph. Ale i tady můžeš narazit, pokud tentýž program děláš i pro Angličany, kde používají "vat" nebo pro Němce s jejich "mwst".

Místo out_buf by to mělo skutečně být outputBuffer, ale můžeš se setkat se zažitou zkratkou "ob", která by se neměla používat v jimém významu, než je právě OutputBuffer. Takže si vyber mezi "outputBuffer" a "ob".

Obecně platí pravidlo, že čím je proměnná "lokálnější", tím může být její název kratší. Viz zmíněné i, j, k, které by se neměly používat v jiném významu, než jako řídicí proměnné cyklu.

Naopak čím je vzdálenější (typicky konstanty, které mají platit v celé aplikaci), tím by měl být jejich název delší, složený z více slov tak, aby vysvětloval, k čemu ta konstanta slouží.

Totéž platí pro veřejné/lokální proměnné či metody. A protože by veřejných proměnných a metod mělo být co nejméně (veřejné proměnné nejlépe žádné nebo skoro žádné) tak ty privátní názvy mohou být krátké.

Nikoli však zkracované. Místo buf použij b nebo buffer, tedy pokud to skutečně má význam bufferu - což v daném případě není splněno. V té proměnné se nenachází buffer, ale jeden datový záznam. Buffer je vyrovnávací paměť - z jedné strany do něj tečou data, z druhé strany vytékají ven ve stejném pořadí, ale jinou rychlostí.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:a4f5:...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 19 hostů

Podobná vlákna

Struct — založil

Fronta(Struct) — založil Barda

C - struct vnořování — založil Axinox

Dyn Struct — založil myth

Struct vo funkcii — založil Eversmann

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý