Unittien näkyvyysalueet?

Mietin tuossa, pitääko uniteissa käyttää aina funktio-rajapintaa vai
voiko olla myös globaaleja muuttujia? Ts. mitkä ovat muuttujien näkyvyysalueet uniteissa? Tuolla esimerkissä ainakin kaikki oli funktioissa:
https://www.tutorialspoint.com/pascal/pascal_units.htm
3331
Äänestä

Muut lukivat myös

Vastaukset 3

Vanhimmat

Funktion sisällä määritellyt on funktion paikallisia, yksikössä (unit) määritellyt muuttujat tavoittaa kaikki yksikön sisältämät funktiot ja procedure rutiinit.

Esimerkki:
var a : string;
implementation
var s : string;

procedure gg;
var t :string;
begin
end.

function ff;
var x : string
begin
end

a -muuttuja näkyy myös muille yksiköille, ja s näkyy vain tässä yksikössä, t -muuttuja näkyy vain gg-rutiinin sisällä ja x -muuttuja näkyy vain ff -funktion sisällä.

Äänestä
  • Anonyymi (18.10.2021 17:52) on aivan oikeassa -juuri näin.

    Pääsääntö: Globaalit muuttujat ovat huono ohjelmointitapa, ja niiden käyttöä on pääsääntöisesti vältettävä.

    Mutta joissain erityistapauksissa Globaalit muuttujat ovat hyvä ja tarpeellinen idea.

    Kannattaa myös huomata:

    Virallisesti Windows API ja DLL:t eivät ole koskaan tukeneet muuttujien exportointia / importointia !

    Jotkut vapaan lähdekoodin ohjelmat ovat ilmeisesti väärinkäyttäneet funktioiden exportointia siten, että on exportoitu muuttujan osoite ikään kuin se olisi funktion osoite.

    JOS esim. C -kielellä tehdyssä DLL:ssä on näin tehty, oma suositukseni on:

    Oletetaan, että muuttujan nimi on X ja se on C-kielellä int -tyyppiä.

    Jos se on exportoitu nimellä X, toimi näin:

    Unit something;

    interface

    function GetAddressOfX:Pointer;

    implementation

    function X(); cdecl; external 'Libary_Made_In_C.DLL';

    function GetAddressOfX:Pointer;
    begin
    Result := @X;
    end;

    Kutsumalla funktiota GetAddressOfX, se palauttaa Pointer -tyyppisen osoittimen, joka osoittaa tuohon sääntöjen vastaisesti exportoituun muuttujaan X.

    Voit sitten tehdä näin:

    var
    P : PInteger;

    begin
    P := GetAddressOfX;
    end;

    esim. ns. singleton -luokan osalta voisi olla hyvä idea:

    globaali muuttuja:

    var
    MySingleton : TMySingleton;
    SingletonTeardown : Boolean;


    ja sitten:

    initialization

    MySingleton : TMySingleton.Create( {parametrit tähän, jos niitä on} );

    finalization
    SingletonTeardown := True;
    FreeAndNil(MySingleton);
    end.

    1-säikeisessä ohjelmassa tämä riittääkin.

    Monisäikeisessä ohjelmassa pitää vielä miettiä, miten voit toisesta säikeestä turvallisesti käyttää MySingleton -muuttujan viittaamaa TMySingleton -tyyppistä luokkaa - kas kun se olio voi yht'äkkiä kadota, kun toinen säie päätyy tuohon

    FreeAndNil(MySingleton); -kohtaan !

    Monisäikeinen ohjelmointi ei tämän takia aina ole helppoa eikä yksinkertaista.

    Pitäisikö kaikki TMySingleton -luokan metodit koodata näin:

    procedure TMySingleton.Esimerkki;
    begin
    FSingletonLock.Acquire;
    try
    // tee varsinainen asia tässä

    finally
    FSingletonLock.Release;
    end;
    end;

    Tuo muuten toimisi, mutta tuo FreeAndNil -käskyn jälkeen mitään TMySingleton -luokan metodia ei saisi kutsua !

    Äänestä

  • Anonyymi kirjoitti:

    Anonyymi (18.10.2021 17:52) on aivan oikeassa -juuri näin.

    Pääsääntö: Globaalit muuttujat ovat huono ohjelmointitapa, ja niiden käyttöä on pääsääntöisesti vältettävä.

    Mutta joissain erityistapauksissa Globaalit muuttujat ovat hyvä ja tarpeellinen idea.

    Kannattaa myös huomata:

    Virallisesti Windows API ja DLL:t eivät ole koskaan tukeneet muuttujien exportointia / importointia !

    Jotkut vapaan lähdekoodin ohjelmat ovat ilmeisesti väärinkäyttäneet funktioiden exportointia siten, että on exportoitu muuttujan osoite ikään kuin se olisi funktion osoite.

    JOS esim. C -kielellä tehdyssä DLL:ssä on näin tehty, oma suositukseni on:

    Oletetaan, että muuttujan nimi on X ja se on C-kielellä int -tyyppiä.

    Jos se on exportoitu nimellä X, toimi näin:

    Unit something;

    interface

    function GetAddressOfX:Pointer;

    implementation

    function X(); cdecl; external 'Libary_Made_In_C.DLL';

    function GetAddressOfX:Pointer;
    begin
    Result := @X;
    end;

    Kutsumalla funktiota GetAddressOfX, se palauttaa Pointer -tyyppisen osoittimen, joka osoittaa tuohon sääntöjen vastaisesti exportoituun muuttujaan X.

    Voit sitten tehdä näin:

    var
    P : PInteger;

    begin
    P := GetAddressOfX;
    end;

    esim. ns. singleton -luokan osalta voisi olla hyvä idea:

    globaali muuttuja:

    var
    MySingleton : TMySingleton;
    SingletonTeardown : Boolean;


    ja sitten:

    initialization

    MySingleton : TMySingleton.Create( {parametrit tähän, jos niitä on} );

    finalization
    SingletonTeardown := True;
    FreeAndNil(MySingleton);
    end.

    1-säikeisessä ohjelmassa tämä riittääkin.

    Monisäikeisessä ohjelmassa pitää vielä miettiä, miten voit toisesta säikeestä turvallisesti käyttää MySingleton -muuttujan viittaamaa TMySingleton -tyyppistä luokkaa - kas kun se olio voi yht'äkkiä kadota, kun toinen säie päätyy tuohon

    FreeAndNil(MySingleton); -kohtaan !

    Monisäikeinen ohjelmointi ei tämän takia aina ole helppoa eikä yksinkertaista.

    Pitäisikö kaikki TMySingleton -luokan metodit koodata näin:

    procedure TMySingleton.Esimerkki;
    begin
    FSingletonLock.Acquire;
    try
    // tee varsinainen asia tässä

    finally
    FSingletonLock.Release;
    end;
    end;

    Tuo muuten toimisi, mutta tuo FreeAndNil -käskyn jälkeen mitään TMySingleton -luokan metodia ei saisi kutsua !

    Korjaus edelliseen:

    "
    implementation

    function X(); cdecl; external 'Libary_Made_In_C.DLL';

    function GetAddressOfX:Pointer;
    begin
    Result := @X;
    end;

    Kutsumalla funktiota GetAddressOfX, se palauttaa Pointer -tyyppisen osoittimen, joka osoittaa tuohon sääntöjen vastaisesti exportoituun muuttujaan X.
    "

    TEORIASSA tuon pitäisi toimia.
    Mutta veikkaanpa, ettei oikeasti toimi, ja siihen on syykin, miksei toimi.

    Tuo johtuu siitä, että tuo lause:

    Result := @X;

    palauttaa kylläkin muistiosoitteen (mutta todennäköisesti väärän asian muistiosoitteen) ja palauttaa tuon muistiosoitteen GetAddressOfX:Pointer -funktion tuloksena.

    Ongelma liittyy tapaan, jolla ainakin Delphi (ja mahdollisesti myös FreePascal) importoi funktioita DLL;stä, jos ei käytetä ajonaikaista importointitapaa eli LoadLibrary() ja GetProcAddress().

    Helpoin tapa kiertää ongelma on nimenomaan käyttää ajonaikaista importointitapaa eli LoadLibrary() ja GetProcAddress() -funktioita, tällöin homma toimii oikein.

    JOS noin ei halua tehdä, kyllä olisi mahdollista kirjoittaa funktio, joka tekee silti oikean asian, mutta se funktio ei ole ihan noin yksinkertainen kuin edellisessä viestissä on esitetty.

    Äänestä

Kommentoi aloitusta


Anonyymi kirjoitti:

Mietin tuossa, pitääko uniteissa käyttää aina funktio-rajapintaa vai
voiko olla myös globaaleja muuttujia? Ts. mitkä ovat muuttujien näkyvyysalueet uniteissa? Tuolla esimerkissä ainakin kaikki oli funktioissa:
https://www.tutorialspoint.com/pascal/pascal_units.htm

Anonyymi
5000

Ilmoita asiaton sisältö

  • Sisältää materiaalia, joka on loukkaavaa, herjaavaa, rasistista, uhkailevaa tai ahdistelevaa.

  • Materiaali sisältää nimiä, yhteystietoja tai muita henkilökohtaisia tietoja. Julkisuuden henkilöistä, julkisissa viroissa toimivista ihmisistä sekä yritysten vastuuhenkilöistä saa keskustella työhön liittyen. Myös yksityiselämään liittyvistä asioista voi keskustella siltä osin, kuin niistä on julkisesti kerrottu.

  • Sisältää lapsille haitallista tai heiltä kiellettyä materiaalia. Seksuaalinen sisältö on sallittua aiheeseen tarkoitetuilla palstoilla, joiden ikäraja on 18 vuotta.

  • Lainvastaista sisältöä voi olla mm. yksityiselämää loukkaavan tiedon levitys, kiihottaminen kansanryhmää vastaan, laiton uhkaaminen, alaikäisiin liittyvä seksuaalinen sisältö/grooming, petokset, identiteettivarkaudet, kunnianloukkaukset ja tekijänoikeusrikkomukset.

  • Sisältö ei liity palstan tai keskusteluketjun aiheeseen.

  • Viesti ei ole suomea tai ruotsia (pl. International Forums), se sisältää mainontaa, se sisältää tekijänoikeuksin suojattua materiaalia, se on massapostitus tai jokin muu syy.

Jaa keskustelu