Uppdrag

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 29 mars 2021; kontroller kräver 23 redigeringar .

Tilldelning  är en bindningsmekanism i programmering som gör att du dynamiskt kan ändra förhållandet mellan namnen på dataobjekt (vanligtvis variabler ) med deras värden. Strängt taget är att ändra värden en bieffekt av tilldelningsoperationen, och i många moderna programmeringsspråk returnerar själva operationen också ett visst resultat (vanligtvis en kopia av det tilldelade värdet). På den fysiska nivån är resultatet av en tilldelningsoperation att skriva och skriva om minnesceller eller processorregister .

Tilldelning är en av de centrala konstruktionerna i imperativa programmeringsspråk , implementerad effektivt och enkelt på von Neumann-arkitekturen som är grunden för moderna datorer .

I objektorienterade programmeringsspråk är tilldelningens semantik en helt annan. Till exempel, i Kotlin- språket, vid tilldelning, kopieras objektet, och i Rust -språket flyttas objektet (move-semantics) och det gamla paketet blir ogiltigt.

Logisk programmering tar ett annat, algebraiskt tillvägagångssätt. Här finns inget vanligt ("destruktivt") uppdrag. Det finns bara okända som ännu inte har beräknats, och motsvarande identifierare för att beteckna dessa okända. Programmet bestämmer bara deras värden, de själva är konstanta. Naturligtvis, i implementeringen, skriver programmet till minnet, men programmeringsspråk återspeglar inte detta, vilket ger programmeraren möjlighet att arbeta med identifierare med konstanta värden och inte med variabler.

Ren funktionell programmering använder inga variabler och behöver ingen explicit tilldelningssats.

Definition

Den allmänna syntaxen för en enkel tilldelning är följande:

<uttryck till vänster> <tilldelningsoperator> <uttryck till höger>

"Uttrycket till vänster" ska efter utvärdering leda till platsen för dataobjektet, till målvariabeln, identifieraren för den minnescell till vilken inspelningen ska göras. Sådana referenser kallas "left-values" ( engelska  lvalue ). Typiska exempel på ett vänsterhänt värde är ett variabelnamn ( x), en sökväg till en variabel i namnrymden och bibliotek ( Namespace.Library.Object.AnotherObject.Property), en arraysökväg med ett uttryck i stället för indexet ( this.a[i+j*k]), men mer komplexa alternativ ges längre fram i detta artikel.

"Uttrycket till höger" måste på ett eller annat sätt beteckna det värde som ska tilldelas dataobjektet. Även om namnet på samma variabel står till höger som till vänster så tolkas det annorlunda - sådana referenser kallas "högerhandsvärden" ( engelska  rvalue ). Språket som används sätter ytterligare begränsningar på uttrycket : sålunda, i statiskt typade språk, måste det ha samma typ som målvariabeln, eller en typ cast till den; på vissa språk (till exempel C eller Python ), kan en annan tilldelningsoperator ( a=b=c) också inkluderas i uttrycket.

Den vanligaste uppdragsoperatören inom programmeringsspråk är =, :=eller ←. Men speciell syntax kanske inte introduceras - till exempel i Tcl :

ställ in <målvariabel> <uttryck>

Denna notation motsvarar att anropa en funktion . På samma sätt, i gammaldags COBOL :

MULTIPERERA 2 MED 2 ATT GER FYRA.

Operationsalgoritm

Beteckning

Valet av uppdragssymbolen är en kontroversiell fråga bland språkdesigners. Det finns en uppfattning om att användningen av en symbol =för uppdrag förvirrar programmerare och väcker också frågan om att välja en symbol för jämförelseoperatören , vilket är svårt att lösa bra .

Således sa Niklaus Wirth [1] :

Ett välkänt dåligt exempel är valet av ett likhetstecken för att beteckna en uppgift, som går tillbaka till Fortran 1957 och fortfarande blint upprepas av en massa språkutvecklare. Denna dåliga idé störtar den urgamla traditionen att använda " = "-tecknet för att beteckna en jämställdhetsjämförelse, ett predikat som utvärderas till " sant " eller " falskt ". Men i Fortran började denna symbol beteckna uppdrag, tvång till jämlikhet. I det här fallet är operanderna i en ojämlik position: den vänstra operanden, variabeln, måste göras lika med den högra operanden, uttrycket. Så x = y betyder inte samma sak som y = x.

Originaltext  (engelska)[ visaDölj] Ett ökänt exempel på en dålig idé var valet av likhetstecknet för att beteckna uppdrag. Det går tillbaka till Fortran 1957 och har blint kopierats av arméer av språkdesigners. Varför är det en dålig idé? Eftersom det stör en sekel gammal tradition att låta "=" beteckna en jämförelse för jämlikhet, ett predikat som är antingen sant eller falskt. Men Fortran gjorde det till att betyda uppdrag, upprätthållande av jämlikhet. I det här fallet är operanderna på ojämlik fot: Den vänstra operanden (en variabel) ska göras lika med den högra operanden (ett uttryck). x = y betyder inte samma sak som y = x. [2]

Implementeringen av denna position av Wirth kan anses som att i Pascal- språket , som han är författare till, är uppdragsoperatören :=, medan det för jämförelse helt enkelt används =.

Valet av symbolen för likhetsoperatören på språket när det används =som en uppgift avgörs av:

Notering av likhet i C == är en källa till frekventa fel på grund av möjligheten att använda tilldelning i kontrollkonstruktioner, men på andra språk löses problemet genom att införa ytterligare begränsningar.

Till exempel, i språkuttrycket PL/1 :

A = B = C

variabeln Аtilldelas det booleska värdet för relationsuttrycket В = С. En sådan notation leder till minskad läsbarhet och används sällan.

Semantiska egenskaper

Långt ifrån alltid "intuitiva" (för programmerare av imperativa språk) sätt att tolka uppdraget är det enda sanna och möjliga.

Utifrån den syntax som används i imperativa språk är det inte alltid möjligt att förstå hur uppgiftssemantiken implementeras om det inte är uttryckligen definierat i språket.

Till exempel, i Forth , innan tilldelning, måste värdet och adressen för en variabel läggas till datastacken, och detta kan göras långt innan den faktiska tilldelningen utförs.

Exempel:

\ Definiera variabeln AAA och tilldela den värdet 10 på nästa rad VARIABEL AAA 10 AAA!

Samma sak lite annorlunda:

tio VARIABEL AAA AAA! Tvetydighet

Tänk på ett exempel:

X=2+1

Detta kan förstås som att "resultatet av beräkningen 2+1 (dvs. 3) tilldelas en variabel X" eller som "operationen 2+1 är tilldelad en variabel X". Om språket är statiskt skrivet , så finns det ingen tvetydighet, det löses av typen av variabel X("heltal" eller "operation"). I Prolog är skrivning dynamiskt , så det finns två tilldelningsoperationer: is - tilldelning av ett ekvivalent värde och = - tilldelning av ett mönster. I detta fall:

X är 2 + 1, X = 3 X=2+1, X=3

Den första sekvensen kommer att kännas igen som sann, den andra - falsk.

Text

När man hanterar objekt av stora storlekar och komplex struktur använder många språk den så kallade " referenssemantiken ". Detta innebär att tilldelning i klassisk mening inte förekommer utan målvariabelns värde anses vara placerat på samma plats som källvariabelns värde. Till exempel ( Python ):

a = [1, 2, 3] b = a a[1] = 1000

Efter det kommer det batt ha ett värde [1, 1000, 3] - helt enkelt för att dess värde faktiskt är värdet av a. Antalet referenser till samma dataobjekt kallas dess kardinalitet, och själva objektet dödas (förstörs eller ges till sopsamlaren ) när dess kardinalitet når noll. Programmeringsspråk på lägre nivå (som C ) tillåter programmeraren att uttryckligen kontrollera om pekaremantik eller kopieringsemantik används.

Operationsersättning

Många språk ger möjlighet att ändra innebörden av ett uppdrag, antingen genom egendomsmekanismen eller genom att överbelasta uppdragsoperatören. Substitution kan behövas för att utföra kontroller av giltigheten av det tilldelade värdet eller andra ytterligare operationer. Överbelastning av uppdragsoperatören används ofta för att tillhandahålla en "djup kopia", det vill säga kopiera värden snarare än referenser, som kopieras som standard på många språk.

Sådana mekanismer gör det möjligt att ge bekvämlighet på jobbet, så för en programmerare är det ingen skillnad mellan att använda en inbyggd operatör och en överbelastad. Av samma anledning är problem möjliga, eftersom den överbelastade operatörens handlingar kan vara helt annorlunda än standardoperatörens handlingar, och funktionsanropet är inte uppenbart och kan lätt misstas för en inbyggd operation.

Utökade mönster

Eftersom tilldelningsoperatören används flitigt, försöker programmeringsspråksutvecklare att utveckla nya konstruktioner för att förenkla skrivningen av typiska operationer (för att lägga till det så kallade " syntaktiska sockret " till språket). Dessutom, i programmeringsspråk på låg nivå, är inkluderingskriteriet ofta förmågan att kompilera till effektiv körbar kod. [3] C- språket är särskilt känt för denna egenskap .

Flera mål

Ett alternativ till den enkla operatorn är möjligheten att tilldela värdet av ett uttryck till flera objekt . Till exempel, i PL/1 , operatören

SUMMA, TOTAL = 0

tilldelar samtidigt noll till variablerna SUMoch TOTAL. I Ada är tilldelning också ett påstående, inte ett uttryck, så notationen för flera tilldelningar är:

SUMMA, TOTAL: Heltal := 0;

En liknande uppgift i Python har följande syntax:

summa = totalt = 0

Till skillnad från PL/1, Ada och Python, där multipla tilldelningar endast betraktas som en stenografi, i C , Lisp och andra, har denna syntax en strikt grund: tilldelningsoperatorn returnerar helt enkelt värdet som tilldelats den (se ovan). Så det sista exemplet är faktiskt:

summa = (totalt = 0)

En rad som denna kommer att fungera i C (om du lägger till ett semikolon i slutet), men kommer att orsaka ett fel i Python.

Parallell tilldelning

Vissa språk, som Ruby och Python , stöder en utökad tilldelningssyntax som kallas parallell tilldelning:

a , b = 1 , 11

Man tror att ett sådant uppdrag utförs samtidigt och parallellt , vilket gör det möjligt att kortfattat implementera, med hjälp av denna konstruktion, operationen att byta ut värdena för två variabler.

Skriva med parallell tilldelning "Traditionell" tilldelning: kräver ytterligare en variabel och tre operationer "Ekonomiskt" uppdrag: kräver ingen extra variabel, men innehåller även tre operationer Ännu mer "ekonomisk" tilldelning: kräver ingen extra variabel, fungerar med bitoperationer
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

Det näst sista aritmetiska alternativet är osäkert i programmeringsspråk eller hårdvaruplattformar som letar efter aritmetiska spill .

Det senare alternativet fungerar bara med typer som stöder bitvisa operationer (till exempel kommer C#double -kompilatorn inte att tillåta dig att utbyta variabelvärden på detta sätt).

Vissa språk (som PHP ) har konstruktioner för att simulera parallell tilldelning:

lista ( $a , $b ) = array ( $b , $a );

Villkorliga mål

Vissa programmeringsspråk, som C++ , tillåter villkorliga mål i tilldelningssatser. Till exempel uttrycket:

( flagga ? count1 : count2 ) = 0 ;

kommer att tilldela ett värde till 0variabeln count1if , och if . flag==truecount2flag==false

En annan variant av villkorlig tilldelning ( Ruby ):

a ||= 10

Denna konstruktion tilldelar ett avärde till en variabel endast om värdet ännu inte har tilldelats eller är lika med false.

Sammansatta uttalanden

Operatorn för sammansatt tilldelning låter dig förkorta en vanlig tilldelningsform. Med den här metoden kan du förkorta notationen för en tilldelning som använder målvariabeln som den första operanden på höger sida av uttrycket, till exempel:

a = a + b

Syntaxen för C -sammansättningstilldelningsoperatorn är föreningen av den önskade binära operatorn och =. Till exempel är följande poster likvärdiga

sum += value; sum = sum + value;

Programmeringsspråk som stöder sammansatta operatorer ( C++ , C# , Python , Java , etc.) har vanligtvis versioner för de flesta av dessa språks binära operatorer+= ( , -=, &=etc.).

Unära operatorer

På språken i C- familjen finns det fyra unära (det vill säga med ett argument) aritmetiska operatorer för att öka och minska tal med en: två " "-operatorer och två " "-operatorer. Operatorer kan skrivas före operanden (prefix) eller efter den (postfix eller suffix). Prefix- och postfix-operatorer skiljer sig åt i utvärderingsordningen. Prefixoperatorer ändrar ett nummer med ett och returnerar det ändrade numret. Postfix-operatörer lagrar ett nummer i en temporär variabel, ändrar det ursprungliga numret och returnerar värdet på den temporära variabeln. ++--

Ett exempel på användning av operatorn : ++

Öka värdet på en variabel med en Motsvarande notation
count ++; count = count + 1;

Även om det inte ser ut som ett uppdrag, det är det. Resultatet av att utföra ovanstående uttalande är detsamma som resultatet av att utföra uppdraget.

Operatörerna " " kallas inkrementoperatorer och " "-operatorerna kallas dekrementoperatorer. Operatorer används ofta i C-språket när de hanterar pekare och arrayindex . ++--

Implementering

Funktionen hos moderna datorer består av att läsa data från minnet eller enheten till register, utföra operationer på dessa data och skriva till minnet eller enheten. Huvudoperationen här är dataöverföring (från register till minne, från minne till register, från register till register). Följaktligen uttrycks det direkt av instruktionerna från moderna processorer . Så för x86- arkitekturen (alla kommandon nedan gäller också för denna arkitektur), är detta en operation movoch dess varianter för att skicka data av olika storlekar. Tilldelningsoperationen (överföring av data från en minnescell till en annan) implementeras praktiskt taget direkt av detta kommando. Generellt sett krävs två instruktioner för att utföra en dataöverföring i minnet: en minne-till-register-flyttning och en register-till-minne-flyttning, men med optimeringar kan antalet instruktioner minskas i de flesta fall.

movl -4(%ebp), %eax
movl %eax, 8(%ebp)

Exempel på kodgenerering ( GCC ), två
instruktioner för tilldelning

Se även

Anteckningar

  1. Niklaus Wirth . Bra idéer: Titta genom glasögonen . Per. Sergei Kuznetsov (2006). Hämtad 23 april 2006. Arkiverad från originalet 27 september 2011.
  2. Niklaus Wirth. Bra idéer, genom glasögonen . Hämtad 4 december 2010. Arkiverad från originalet 25 juni 2012.
  3. I optimeringssyfte kombineras många operationer med uppdrag. Stenografiuppdrag har ofta en motsvarighet i maskininstruktioner. Så, ökning med en implementeras av maskininstruktionen inc, minska med en - dec, addition med tilldelning - add, subtraktion med tilldelning - , villkorlig suböverföringsinstruktioner - cmovaetc.cmovno

Litteratur

  • Robert W. Sebesta. Grundläggande begrepp för programmeringsspråk \u003d Begrepp av programmeringsspråk. - 5:e uppl. - M. : Williams , 2001. - 672 sid. - ISBN 0-201-75295-6 .
  • M. Ben-Ari. Programmeringsspråk. Praktisk jämförande analys. — M.: Mir, 2000. — 366 sid. sid. 71-74.
  • V. E. Wolfenhagen. Design av programmeringsspråk. Beskrivningsmetoder. - M .: JSC Center YurInfoR, 2001. - 276 sid. ISBN 5-89158-079-9 . sid. 128-131.
  • E. A. Opaleva, V. P. Samoilenko. Programmeringsspråk och översättningsmetoder. - St Petersburg: BHV-Petersburg, 2005. - 480 sid. ISBN 5-94157-327-8 . s. 74-75.
  • T. Pratt, M. Zelkowitz. Programmeringsspråk: utveckling och implementering. - 4:e uppl. - St Petersburg: Peter, 2002. - 688 sid. ISBN 5-318-00189-0 , ISBN 0-13-027678-2 . sid. 201-204.