Tipuri de coarde în Delfi - Revista

În acest articol, vor fi evidențiate următoarele aspecte:

  1. Care există tipuri de coarde în Delphi, a pus și modul în care acestea diferă unul de altul
  2. conversie String de la un tip la altul
  3. Unele metode folosesc tipuri AnsiString de linii:
    1. Funcții pentru lucrul cu siruri de caractere care de multe ori uita sau nu stiu
    2. linii de transmisie ca parametri
    3. Folosind înregistrările liniilor
    4. Scrierea într-un fișier și citește din fișierul
    5. Folosind siruri ca parametrii și funcțiile rezultate plasate în DLL.

Ei bine, mă întreb? Atunci să mergem.

Ce tipuri șir există în Delphi, a pus și modul în care acestea diferă unul de altul?

In Delphi 1.0 exista doar un singur tip string String, complet echivalent cu tipul de același nume, în Turbo Pascal și Borland Pascal. Cu toate acestea, acest tip are limitări semnificative, pe care le voi discuta mai târziu. Pentru a evita aceste limitări, Delphi 2, dezvoltatorii de Borland aranjate revoluție mici. Acum, din moment ce Delphi 2, există trei tipuri de bază de coarde: ShortString, AnsiString și WideString. În plus, tipul String devenit acum logic. Ie în funcție de setările de compilatorul mod corespunzător (modul de siruri de caractere mari), este egală sau de tip ShortString (pentru compatibilitate cu programe mai vechi) sau la tipul AnsiString (implicit). Modul de conducere, puteți utiliza directiva de compilare (formă scurtă), sau din fereastra de setări de proiect - tab-ul „compilatoare“ -> bifați „siruri de mare“. Dacă este activat, apoi echivalează cu un AnsiString String, String este egal cu un alt ShortString. Această regulă are o excepție: în cazul în care în definiția de tipul String Setați dimensiunea maximă a șirului, de ex String [25], atunci, indiferent de modul de compilator, tipul va fi asimilată cu ShortString dimensiune corespunzătoare.

Pentru că, după cum veți afla în viitor, și AnsiString tipuri de ShortString au o diferență fundamentală în punerea în aplicare, eu nu recomand să utilizați un tip String logic, fără a specifica dimensiunea, dacă sunteți, desigur, nu scrie programe sub Delphi 1. Dacă încă utilizați tip String, apoi m-am foarte recomandăm direct în codul modulului dvs. pentru a specifica directiva de compilare care stabilește modul de compilator implicit. Mai ales dacă utilizați caracteristicile punerii în aplicare a tipului șir corespunzător. Dacă nu, o zi, atunci când codul se încadrează în mâinile unui alt programator, nu va exista nici o garanție că va stabili compilator, precum și a ta.

Deoarece implicit, după instalarea Delphi, siruri de caractere mari este activată, majoritatea tinerilor programatori nici măcar nu știu că șirul poate fi altceva decât un AnsiString. Prin urmare, restul acestui articol, orice referire la un șir fără a specifica dimensiunea, înseamnă că este egal cu tipul AnsiString, dacă nu se specifică în mod explicit altfel. Ie se consideră că setarea compilator corespunde la setarea implicită.

menționa imediat diferența dintre tipurile AnsiString și WideString. Aceste tipuri au în mod substanțial aceeași implementare, și diferă numai prin faptul că WideString utilizate pentru a reprezenta șiruri în codificarea UNICODE folosind o reprezentare de 16 biți fiecărui caracter (WideChar). Această codificare este utilizat în cazurile în care aveți nevoie de prezența simultană în aceeași linie de caractere din două sau mai multe limbi (altele decât engleza). De exemplu, rândurile conțin ambele simboluri ale engleză, română și alte limbi europene. Pentru această oportunitate de a plăti - cantitatea de memorie ocupată de o astfel de șir este de două ori dimensiunea liniilor convenționale ocupate. Utilizarea WideString nu este comun, așa că voi vorbi în principal despre liniile de tip AnsiString. Dar, pentru că ei au aceeași realizare, aproape tot ceea ce a fost spus despre AnsiString va fi valabilă pentru WideString, luând în mod natural în considerare diferențele în dimensiunea fiecărui caracter.

Același lucru este valabil și pentru diferența dintre pChar și pWideChar.

String AnsiString, utilizat de obicei pentru a reprezenta siruri codate în ANSI, sau altele (de exemplu, OEM), care utilizează un octet (8 biți), care codifică un simbol. O astfel de metodă de codificare se numește un set de caractere pe un singur octet, sau SBCS. Dar mulți nu sunt conștienți de existența unei alte metode de codificare siruri de caractere în mai multe limbi (altele decât UNICODE), utilizate în sistemele de operare Windows și Linux. Această metodă se numește seturi de caractere multioctet, sau MBCS. În această metodă, unele caractere sunt reprezentate de un octet, iar unele două sau mai multe. Spre deosebire de UNICODE, string codificat într-un mod care necesită mai puțină memorie pentru stocarea lor, dar necesită o procesare mai complexe. Deci, AnsiString tip string poate fi utilizat pentru stocarea acestor rânduri. Nu voi insista asupra acestei metode de codificare, deoarece este rar folosit. Personal, n-am întâlnit programele utilizând metoda de codificare.

probabil experți Delphi va aminti mi încă o dată, și despre tipurile de pChar (pWideChar) și matrice [. ] Char. Cu toate acestea, eu cred că nu este destul de tipuri de coarde, dar eu voi spune despre ei, deoarece acestea sunt atât de des utilizate în combinație cu tipuri de coarde.

Deci, aici sunt principalele caracteristici ale tipului string:

Mărimea maximă a șirului

Cantitatea de memorie necesară pentru a stoca șirul

String [n], unde 0 este 0, deci Delphi și nu eliberează memoria ocupată de un șir de caractere.

Cu toate acestea, acest contor este folosit pentru a rezolva problemele asociate cu următoarea situație:

Atunci când se lucrează cu anumite siruri de caractere ca și constante, algoritmul este oarecum diferit. Iată un exemplu:

S-ar părea că, la finalul procedurii, instanță a șirului „Bob“ trebuie să fie distruse. Dar, în acest caz, nu este. La urma urmei, data viitoare procedura de atribuire va trebui să re-ia undeva linia „Vasya“. Pentru a face acest lucru, chiar și atunci când sunt compilate, Delphi pune o copie a șirului „Bob“ în constantele de program, chiar și în cazul în care este imposibil să se schimbe, cel puțin în metode simple. Dar ce putem spune despre atunci când la sfârșitul procedurii pentru a determina faptul că șirul „Bob“ - un șir de caractere constantă, și este imposibil de a distruge? Este foarte simplu. Pentru siruri, contor de referință este setată la -1. Această valoare este „off“ algoritm normale funcționează cu „numărul de referință“. El nu este crescut de atribuire, și nu este redus prin distrugerea variabilei. Cu toate acestea, atunci când încearcă să schimbe variabila (Rețineți s2 [1]: = „X“), contravaloarea -1 va fi considerată întotdeauna o indicație care se referă la un șir de mai mult de o variabilă (de fapt nu este egal cu 1). Prin urmare, într-o astfel de situație va crea întotdeauna o instanță unică a unui șir de caractere, desigur, fără a decrementare numărul de referință al vechi. Acest lucru vă protejează de modificările constante șir instanță.

Din păcate, acest algoritm nu funcționează întotdeauna. Dar mai multe despre asta, vom vorbi mai târziu, atunci când se analizează conversia tipurilor șir.

În cazul în care este de magazine Delphi un „COUNT de referință“? Mai mult decât atât, pentru fiecare linie de propria dvs.! În mod firesc, împreună cu șirul. Aceasta este ceea ce acest domeniu de memorie care stochează o copie a liniei „ABC“:

Număr referință de -1

Cu câmpul de offset de la -8, ar trebui să fie deja clar. Această valoare este stocată într-un cuvânt dublu (4 octeți), aceeași contra, ceea ce permite optimizarea stocarea liniilor identice. Acest contor este de tip Integer, adică poate fi negativ. De fapt, folosind doar un singur negativ - valori „-1“, și pozitive. 0 nu este utilizat.

Acum, uita-te pentru câmpul, care se află la -4 compensate. Această lungime string valoare de patru octeți (aproape ca în ShortString). Cred că veți observa că cantitatea de memorie alocată pentru șirul nu are nici o redundanță. Ie compilatorul alocă un șir de număr minim necesar de bytes de memorie. Acest lucru este cu siguranță bun, dar atunci când încercați să „intensifice“ linie: s1: = s1 + „d“, compilator, mai degrabă run-time bibliotecă (RTL) trebuie să realoce memorie. Pentru că acum linia necesită mai multă memorie, de mult ca un octet. Pentru a realoca memoria trebuie să știți dimensiunea actuală a șirului. Probabil, este pentru ceea ce nu este necesar de fiecare dată când linia de scanare, determinarea dimensiunii sale, dezvoltatorii Delphi și liniile de câmp lungime încorporate în această structură. Lungimea șir este stocată ca valoare Integer, deci limita dimensiunea maximă a rândurilor - 2 GB. Să sperăm că nu vom upremsya curând în această restricție. Apropo, tocmai pentru că memoria pentru șirul este alocat dinamic, și au primit o mai mult la numele său: linia dinamică.

Rămâne să-i spun mai multe despre câteva caracteristici ale variabilelor AnsiString. Cea mai importantă caracteristică a acestui tip de valori este posibilitatea de a le aduce la tipul pointer. În acest fel, desigur, pentru că în „sufletul“ ei sunt indicii, ca și în cazul în care acestea nu ascund. De exemplu, în cazul în care sunt descrise variabilele: s: AnsiString și p: pointer. Performanța operatorului p: = Pointerilor (e) va duce la faptul că variabila p va indica instanta string. Cu toate acestea, este foarte important să se știe: contracara acest rând de link-uri nu vor fi majorate. Dar mai multe despre asta, vom vorbi despre mai târziu.

Deoarece variabilele de acest tip sunt de fapt indicii, pentru ei și într-adevăr este important ca Nil - un pointer la „nicăieri.“ Valoarea în tipul AnsiString variabilă în sensul egal un șir gol. Mai mult decât atât, pentru a evita irosirea de memorie și de timp pentru a efectua numărul de referință, precum și mărimea câmpului șirului este întotdeauna 0, atunci când atribuiți o variabilă șir gol de acest tip, de fapt, este setat la Nil. Nu este evident, pentru că este, de obicei, nu vizibil, dar după cum vom vedea mai târziu, o caracteristică foarte importantă.

Acum, se pare, sunt conștienți de toate liniile. Este timpul pentru a trece la mai interesanta parte a articolului - cum să trăiască cu totul?

conversie String de la un tip la altul

Aici, ca de obicei, și simple și complexe.

Conversia între tipurile șir "reale" String [n], ShortString și AnsiString efectuate cu ușurință și în mod transparent. nu trebuie să facem nici o acțiune explicită, Delphi va face totul pentru tine. Trebuie doar să înțelegem că într-un pic pauze mai lungi. De exemplu:

Ca urmare a prezentului cod, s3 variabilă va șir de caractere „abc“, mai degrabă decât „abcdef“. Odată cu transformarea pChar în String [n], ShortString și AnsiString, de asemenea, tot nu este rău. Pur și simplu atribuie, și totul va fi bine.

Dificultăți începe atunci când vom începe să se transforme tipurile de coarde „reale“ în pChar. Tipul de variabilă valori rând pChar directe de atribuire nu este permisă de compilator. Pe operatorul p: = s unde p este de tip pChar, și s: AnsiString, compilatorul va emite un mesaj: „Tipuri incompatibile:«String»si«PChar»“ - tipuri incompatibile de „String“ și „PChar“. Pentru a evita această problemă, trebuie să utilizați un tip de conversie explicită: p: = pChar (e). Deci, recomandăm dezvoltatorii Delphi. În general, ei au dreptate. Dar, dacă vă amintiți, siruri de caractere ca dinamice sunt stocate - un nul-terminate, ca pChar. Și totuși, și ce să AnsiString aplicabile tip de conversie pointer. Devine evident că toate, poate la fel de multe ca trei moduri de a converti un șir de caractere pentru a pChar:

Toate acestea sunt corect sintactic. Și se pare că toate cele trei indicatorul (p1, p2 și p3) va avea ca rezultat aceeași valoare. Dar acest lucru nu este cazul. Totul depinde de ceea ce este în s. Pentru a fi mai precis, dacă valoarea e linie goală sau nu:

Că ați înțeles cauza acestui fenomen, voi descrie modul în care Delphi efectuează fiecare dintre aceste transformări. La început am să vă reamintesc că variabilele AnsiString reprezentând linii goale într-adevăr au valoare de Nil. Deci:

Pentru a face pChar de conversie (e), compilatorul generează un apel intern o funcție specială @LstrToPChar. Această funcție verifică - dacă variabila șir are o valoare de Nil, apoi în schimb, se returnează un pointer la locația actuală în memoria unui șir gol. Ie pChar (e) nu returnează un pointer egal cu zero.

Aceasta cauzează o eroare de acces la memorie atunci când linia marcată 1. Deci, avem de a utiliza această caracteristică.

Aici, din moment ce parametrul a trecut de valoare, apelul va fi creat o copie locală a variabilei (pointer) MSG. Aceasta este ceea ce voi spune mai târziu. Această variabilă, la finalizarea procedurilor vor fi distruse, ceea ce duce la eliberarea de copii „personalizate“ de copii ale șir transmise și transformate.

Funcțiile acestui grup sunt folosite pentru a compara siruri de caractere. Rezultatul va fi una din valorile:

> 0 dacă S1> S2
255 de caractere trebuie să plătească.

Dacă suficient și 255 de caractere, apoi utilizați un ShortString sau String [n].

Folosind înregistrările liniilor

Problema apare atunci când un câmp (sau câmpuri) sunt de linie de tip dinamic. În acest caz, de multe ori există o problemă similară cu problema liniilor dinamice scrise la dosar - nu toate datele sunt în înregistrare, liniile dinamice sunt reprezentate în ea doar indicii. Pentru a rezolva problema, precum și o înregistrare a rândurilor din fișier. Păcat numai este că atunci va fi imposibil să se opereze (scrie / citi) întregul jurnal. Linia va trebui să se ocupe separat. Puteți face ca acest lucru:

Folosind siruri ca parametrii și funcțiile rezultate plasate în DLL.

Sensul general al Epic că, dacă dll dvs. exportatoare cel puțin o procedură sau un parametru funcție corespunzătoare tipului de orice (de exemplu, AnsiString) bar dinamic, sau o funcție care returnează rezultatul acelui tip. Trebuie să fie sigur și dll, și folosind programul său, primul modul din lista de import (utilizări) indică modul ShareMem. Și, în consecință, de a livra cu programul său și un alt dll BORLNDMM.DLL biblioteca standard.

Nu te-ai gândi la întrebări: „De ce toate problemele?“; „Ce se va întâmpla dacă nu faci?“ și „Poate acest lucru să fie evitată?“; „Dacă da, cum?“ Dacă nu v-ați gândit, e timpul să o facă.

Încearcă să înțelegi ce se va întâmpla cu cazuri de linii dinamice în acest exemplu:

Totul pare a fi bun. Dar, atâta timp cât ambele proceduri sunt situate într-un singur modul executabil (EXE-fișier). În cazul în care o astfel de procedură în locul Y dll, și procesul X lasă să EXE, nu vor fi probleme.

Faptul că alocarea și Dealocarea pentru cazuri de linii dinamice angajate în managerul de memorie internă Delphi-aplicații. Utilizați managerul standard de Windows este foarte scump. Și el este universal și, prin urmare, lent, și linii necesită adesea realocarea. Dezvoltatorii de Delphi și au creat propria lor. El conduce o listă de distribuție și memoria disponibilă a aplicației. Ei bine, problema este că DLL-ul este folosit un manager de memorie, si EXE-ul. Despre unul pe altul, ei nu știu nimic. Prin urmare, eliberarea unui bloc de memorie nealocat încercați managerul său va duce la o perturbare gravă a activității sale. Mai mult decât atât, această tulburare se poate manifesta, nu dintr-o dată, și un mod destul de neobișnuit.

În acest caz, memoria pentru șirul „100“ va fi evidențiată manager de EXE-fișier, și va fi lansat managerul DLL. Același lucru se va întâmpla cu memoria sub șirul "100 $, numai în sens invers.

Pentru a depăși această problemă, dezvoltatorii Delphi au creat biblioteca BORLNDMM.DLL. Acesta include un alt manager de memorie :). Folosind același modul ShareMem conduce la faptul că înlocuiește built-in EXE (DLL), managerul de memorie pentru managerul situat în BORLNDMM.DLL. Ie Acum, și EXE fișiere și DLL, se va utiliza un singur manager de memorie comună.

Este important să rețineți că dacă nu ar fi în afara modulelor de program (EXE sau DLL) au modulul ShareMem importă lista, toate lucrările vor veni la nimic. Din nou, va rula mai mulți administratori de memorie. Din nou, va fi un dezastru.

Ei bine, în cele din urmă. Acum, că știți despre siruri de caractere aproape la fel de mult ca mine :).

Desigur, acest subiect nu este epuizată. De exemplu, eu nu am spus nimic despre siruri de caractere multioctet (MBCS) utilizate pentru aplicații mai multe limbi. Poate ceva a uitat să-i spun. Dar, nu vă faceți griji. Am primit cunoștințele lor prin studierea cărți, texte proprii și alte programe, codul generat de compilator, etc. Ie toate open source. Deci, totul e disponibil pentru tine. Principalul lucru este că sunteți curioși, și a întrebat de multe ori te întrebarea „Cum?“, „De ce?“ „De ce?“. Apoi, în jurul tău va fi capabil să rezolve ei înșiși.