A hozzárendelés egy kötési mechanizmus a programozásban , amely lehetővé teszi az adatobjektumok (általában változók ) nevének és értéküknek a kapcsolatának dinamikus megváltoztatását. Szigorúan véve az értékek megváltoztatása a hozzárendelési művelet mellékhatása, és sok modern programozási nyelvben maga a művelet is visszaad valamilyen eredményt (általában a hozzárendelt érték másolatát). Fizikai szinten egy hozzárendelési művelet eredménye a memóriacellák vagy processzorregiszterek írása és átírása .
A hozzárendelés az imperatív programozási nyelvek egyik központi konstrukciója , amelyet hatékonyan és egyszerűen a modern számítógépek alapját képező Neumann-architektúrán valósítanak meg .
Az objektum-orientált programozási nyelvekben a hozzárendelés szemantikája egészen más. Például a Kotlin nyelvben hozzárendeléskor az objektumot másolják, a Rust nyelvben pedig az objektumot elmozdítják (move-semantics), és a régi köteg érvénytelenné válik.
A logikai programozás más, algebrai megközelítést alkalmaz. Itt nincs szokványos ("destruktív") megbízás. Csak olyan ismeretlenek vannak, amelyeket még nem számítottak ki, és ezeknek az ismeretleneknek megfelelő azonosítók . A program csak az értékeiket határozza meg, ők maguk állandóak. Természetesen a megvalósítás során a program a memóriába ír, de a programozási nyelvek ezt nem tükrözik, lehetőséget adva a programozónak , hogy állandó értékek azonosítóival dolgozzon, és nem változókkal.
A tiszta funkcionális programozás nem használ változókat, és nincs szüksége kifejezett hozzárendelési utasításra.
Egy egyszerű feladat általános szintaxisa a következő:
<kifejezés a bal oldalon> <hozzárendelési operátor> <kifejezés a jobb oldalon>A "baloldali kifejezés" a kiértékelés után az adatobjektum helyéhez, a célváltozóhoz, a memóriacella azonosítójához kell, hogy vezessen, amelybe a felvétel készül. Az ilyen hivatkozásokat "baloldali értékeknek" ( angolul lvalue ) nevezik. A bal oldali értékek tipikus példái a változó neve ( x), egy változó elérési útja a névtérben és a könyvtárakban ( Namespace.Library.Object.AnotherObject.Property), egy tömb elérési útja egy kifejezéssel az index helyén ( this.a[i+j*k]), de az összetettebb opciókat később adjuk meg. cikk.
A "jobboldali kifejezésnek" így vagy úgy kell jelölnie az adatobjektumhoz rendelendő értéket. Így még akkor is, ha ugyanannak a változónak a neve található a jobb oldalon, mint a bal oldalon, másként értelmezik – az ilyen hivatkozásokat "jobboldali értékeknek" ( angolul rvalue ) nevezik. A használt nyelv további megszorításokat támaszt a kifejezéssel kapcsolatban : így a statikusan beírt nyelvekben a célváltozóval azonos típusúnak kell lennie, vagy típusnak kell szerepelnie; bizonyos nyelveken (például C vagy Python ) egy másik hozzárendelési operátor ( a=b=c) is szerepelhet a kifejezésben.
A programozási nyelvekben a leggyakoribb hozzárendelési operátor a =, :=vagy ←. De speciális szintaxist nem lehet bevezetni - például a Tcl -ben :
állítsa be a <célváltozót> <kifejezést>Ez a jelölés egyenértékű egy függvény meghívásával . Hasonlóképpen a régi stílusú COBOL -ban :
SZOROZZ 2-T 2-VEL, NEGYET ADVA.A hozzárendelés szimbólumának megválasztása vita tárgya a nyelvtervezők körében. Egyes vélemények szerint a szimbólumok =hozzárendelési használata megzavarja a programozókat , és felveti az összehasonlító operátor szimbólumválasztásának kérdését is , amit nehéz jól megoldani .
Így Niklaus Wirth kijelentette [1] :
Jól ismert rossz példa az egyenlőségjel választása a feladat megjelölésére, amely Fortran 1957-ig nyúlik vissza, és még mindig vakon ismételgeti a nyelvfejlesztők tömege. Ez a rossz ötlet megdönti azt az ősrégi hagyományt, hogy a „ = ” jelet egy egyenlőség-összehasonlítás jelölésére használjuk, egy olyan állítmányt, amely „ igazra ” vagy „ hamisra ” értékel. De Fortranban ez a szimbólum a megbízást, az egyenlőségre való kényszert kezdte jelölni. Ebben az esetben az operandusok egyenlőtlen helyzetben vannak: a bal oldali operandust, a változót egyenlővé kell tenni a jobb oldali operandusszal, a kifejezéssel. Tehát az x = y nem ugyanazt jelenti, mint az y = x.
Eredeti szöveg (angol)[ showelrejt] A rossz ötlet hírhedt példája volt az egyenlőségjel kiválasztása a hozzárendelés jelölésére. Az 1957-es Fortranig nyúlik vissza, és vakon másolták nyelvtervezők seregei. Miért rossz ötlet? Mert megdönt egy évszázados hagyományt, hogy a „=” az egyenlőség összehasonlítását jelölje, egy állítmányt, amely igaz vagy hamis. De Fortran a megbízást, az egyenlőség érvényesítését jelentette. Ebben az esetben az operandusok egyenlőtlenül állnak: A bal oldali operandust (változót) egyenlővé kell tenni a jobb oldali operandusszal (kifejezéssel). x = y nem ugyanazt jelenti, mint y = x. [2]Wirth ezen álláspontjának megvalósítása úgy tekinthető, hogy a Pascal nyelvben , amelynek ő a szerzője, a hozzárendelés operátora :=, míg összehasonlítás céljából egyszerűen =.
Az egyenlőség operátor szimbólum kiválasztását a nyelvben, ha =hozzárendelésként használják, a következők döntik el:
Az egyenlőség jelölése C == -ben gyakori hibák forrása a hozzárendelés vezérlőkonstrukciókban való felhasználásának lehetősége miatt, de más nyelveken a probléma további korlátozások bevezetésével megoldható.
Például a PL/1 nyelvi kifejezésben :
A = B = Ca változóhoz a relációkifejezés logikai értékétА rendeljük hozzá . Az ilyen jelölések csökkentik az olvashatóságot , és ritkán használják. В = С
A feladat értelmezése korántsem mindig „intuitív” (az imperatív nyelvek programozói számára) az egyetlen igaz és lehetséges.
Az imperatív nyelvekben használt szintaxisból nem mindig lehet megérteni, hogyan valósul meg a hozzárendelési szemantika , hacsak nincs kifejezetten definiálva a nyelvben.
Például a Forth -ban a hozzárendelés előtt egy változó értékének és címének az adatverembe kell kerülnie, és ez jóval a tényleges hozzárendelés végrehajtása előtt megtehető.
Példa:
\ Az AAA változó definiálása és a következő sorban a 10-es érték hozzárendelése VÁLTOZÓ AAA 10 AAA!Ugyanaz egy kicsit másképp:
tíz VÁLTOZÓ AAA AAA! KétértelműségVegyünk egy példát:
X=2+1Ez felfogható úgy, hogy "a 2+1 (azaz 3) számítás eredménye egy változóhoz van hozzárendelve X", vagy úgy, hogy "a 2+1 művelet hozzá van rendelve egy változóhoz X". Ha a nyelv statikusan van beírva , akkor nincs kétértelműség, azt a változó típusa X("egész" vagy "művelet") oldja fel. A Prologban a gépelés dinamikus , így két hozzárendelési művelet létezik: is - egyenértékű érték hozzárendelése és = - minta hozzárendelése. Ebben az esetben:
X értéke 2 + 1, X = 3 X=2+1, X=3Az első sorozatot igaznak, a másodikat hamisnak ismeri el.
SzövegAmikor nagy méretű és összetett szerkezetű objektumokkal foglalkozik, sok nyelv az úgynevezett " referenciaszemantikát " használja. Ez azt jelenti, hogy a klasszikus értelemben vett hozzárendelés nem történik meg, de a célváltozó értékét a forrásváltozó értékével azonos helyen lévőnek tekintjük. Például ( Python ):
a = [1, 2, 3] b = a a[1] = 1000Ezt követően blesz értéke [1, 1000, 3] – egyszerűen azért, mert valójában az értéke az értéke a. Az ugyanarra az adatobjektumra vonatkozó hivatkozások számát számosságnak nevezzük, és magát az objektumot megölik (megsemmisítik vagy a szemétgyűjtőnek adják ), amikor a számosság eléri a nullát. Az alacsonyabb szintű programozási nyelvek (például C ) lehetővé teszik a programozó számára, hogy kifejezetten szabályozza, hogy mutatószemantikát vagy másolási szemantikát használjon-e.
Művelet helyettesítésSok nyelv lehetővé teszi a hozzárendelés jelentésének megváltoztatását akár a tulajdonságmechanizmuson keresztül, akár a hozzárendelés operátorának túlterhelésén keresztül . Csere szükséges lehet a hozzárendelt érték érvényességének ellenőrzéséhez vagy bármely más további művelethez. A hozzárendelési operátor túlterhelését gyakran használják „mély másolat” biztosítására, azaz a hivatkozások helyett értékek másolására, amelyeket alapértelmezés szerint sok nyelven másolnak.
Az ilyen mechanizmusok lehetővé teszik a munka kényelmét, így a programozó számára nincs különbség a beépített és a túlterhelt operátor használata között. Ugyanezen okból lehetségesek a problémák, mivel a túlterhelt operátor műveletei teljesen eltérhetnek az alapértelmezett operátor műveleteitől, és a függvényhívás nem nyilvánvaló, és könnyen összetéveszthető egy beépített művelettel.
Mivel a hozzárendelési operátort széles körben használják, a programozási nyelvek fejlesztői új konstrukciókat próbálnak kidolgozni, hogy egyszerűsítsék a tipikus műveletek írását (az úgynevezett " szintaktikai cukrot " hozzáadva a nyelvhez). Ezenkívül az alacsony szintű programozási nyelvekben a befogadási kritérium gyakran a hatékony végrehajtható kódokká való fordítás képessége. [3] A C nyelv különösen híres erről a tulajdonságáról .
Az egyszerű operátor egyik alternatívája az a képesség, hogy egy kifejezés értékét több objektumhoz is hozzárendeljük . Például a PL/1 -ben az operátor
ÖSSZESEN = 0egyidejűleg nullát rendel a változókhoz SUMés TOTAL. Az Adában a hozzárendelés is utasítás, nem kifejezés, így a többszörös hozzárendelés jelölése a következő:
ÖSSZESEN: Egész szám := 0;Egy hasonló hozzárendelés a Pythonban a következő szintaxissal rendelkezik:
összeg = összesen = 0Ellentétben a PL/1-től, az Ada-tól és a Python-tól, ahol a többszörös hozzárendelés csak gyorsírásnak minősül, a C -ben, Lisp -ben és másokban ennek a szintaxisnak szigorú alapja van: a hozzárendelési operátor egyszerűen visszaadja a hozzárendelt értéket (lásd fent). Tehát az utolsó példa valójában:
összeg = (összesen = 0)Egy ilyen sor működik C-ben (ha pontosvesszőt ad a végére), de Pythonban hibát okoz.
Egyes nyelvek, például a Ruby és a Python támogatják a párhuzamos hozzárendelésnek nevezett kiterjesztett hozzárendelési szintaxist:
a , b = 1 , 11Úgy gondolják, hogy egy ilyen hozzárendelés egyidejűleg és párhuzamosan történik , ami lehetővé teszi, hogy ezzel a konstrukcióval röviden végrehajtsuk két változó értékének cseréjét.
Írás párhuzamos hozzárendeléssel | "Hagyományos" hozzárendelés: további változót és három műveletet igényel | „Gazdaságos” hozzárendelés: nem igényel további változót, de három műveletet is tartalmaz | Még "gazdaságosabb" hozzárendelés: nem igényel további változót, bitműveletekkel működik |
---|---|---|---|
a, b = b, a | t = a a = b b=t | a = a + b b = a - b a = a - b | a ^= b b ^= a a ^= b |
Az utolsó előtti aritmetikai lehetőség nem biztonságos olyan programozási nyelveken vagy hardverplatformokon , amelyek ellenőrzik az aritmetikai túlcsordulást .
Ez utóbbi opció csak olyan típusokkal működik, amelyek támogatják a bitenkénti műveleteket (például a C#double fordító nem teszi lehetővé a változóértékek ilyen módon történő cseréjét).
Egyes nyelvek (például a PHP ) rendelkeznek konstrukciókkal a párhuzamos hozzárendelés szimulálására:
lista ( $a , $b ) = tömb ( $b , $a );Egyes programozási nyelvek, például a C++ , lehetővé teszik a feltételes célokat a hozzárendelési utasításokban. Például a kifejezés:
( flag ? count1 : count2 ) = 0 ;értéket rendel a 0változóhoz count1if , és if . flag==truecount2flag==false
A feltételes hozzárendelés egy másik változata ( Ruby ):
a ||= 10Ez a konstrukció csak akkor rendel aértéket egy változóhoz, ha az érték még nincs hozzárendelve, vagy egyenlő a -val false.
Az összetett hozzárendelési operátor lehetővé teszi egy gyakran használt hozzárendelési forma rövidítését. Ezzel a módszerrel lerövidítheti egy olyan hozzárendelés jelölését, amely a célváltozót használja első operandusként a kifejezés jobb oldalán, például:
a = a + bA C összetett hozzárendelési operátor szintaxisa a kívánt bináris operátor és a =. Például a következő bejegyzések egyenértékűek
sum += value; | sum = sum + value; |
Az összetett operátorokat támogató programozási nyelvek ( C++ , C# , Python , Java stb.) általában rendelkeznek verziókkal a legtöbb nyelv bináris operátorához+= ( , -=, &=stb.).
A C család nyelveiben négy unáris (vagyis egy argumentumot véve) aritmetikai operátor létezik a számok eggyel növelésére és csökkentésére: két „ ” operátor és két „ ” operátor. Az operátorok írhatók az operandus elé (előtag) vagy utána (utótag vagy utótag). A prefix és postfix operátorok az értékelés sorrendjében különböznek. Az előtag operátorai eggyel módosítanak egy számot, és a módosított számot adják vissza. A Postfix operátorok egy számot tárolnak egy ideiglenes változóban, módosítják az eredeti számot, és visszaadják az ideiglenes változó értékét. ++--
Példa az operátor használatára : ++
Egy változó értékének növelése eggyel | Egyenértékű jelölés |
---|---|
count ++; | count = count + 1; |
Bár nem tűnik feladatnak, de az. A fenti utasítás végrehajtásának eredménye ugyanaz, mint a hozzárendelés végrehajtásának eredménye.
A " " operátorokat növelő operátoroknak, a " " operátorokat pedig csökkentő operátoroknak nevezzük. Az operátorokat gyakran használják a C nyelvben mutatókkal és tömbindexekkel való foglalkozás során . ++--
A modern számítógépek működése abból áll, hogy a memóriából vagy az eszközből adatokat olvasnak be regiszterekbe, műveleteket hajtanak végre ezen az adatokon, és írnak a memóriába vagy eszközre. A fő művelet itt az adatátvitel (regiszterekből a memóriába, memóriából regiszterbe, regiszterből regiszterbe). Ennek megfelelően ezt közvetlenül a modern processzorok utasításai fejezik ki . Tehát az x86 architektúra esetében (az alábbi parancsok erre az architektúrára is vonatkoznak) ez egy művelet movés változatai különböző méretű adatok küldésére. A hozzárendelési műveletet (adatátvitel egyik memóriacellából a másikba) gyakorlatilag közvetlenül ez a parancs hajtja végre. Általánosságban elmondható, hogy a memóriában történő adatátvitel végrehajtásához két utasítás szükséges: egy memória-regiszter és egy regiszter-memória mozgás, de optimalizálásokkal az utasítások száma a legtöbb esetben csökkenthető.
movl -4(%ebp), %eax utasítás a hozzárendeléshez |