Kiedyś bardzo ważne były krótkie nazwy instrukcji / rejestru. Te powody już nie obowiązują, ale krótkie tajemnicze nazwy są nadal bardzo powszechne w programowaniu niskiego poziomu.
Dlaczego to? Czy tylko dlatego, że stare nawyki trudno przełamać, czy są lepsze powody?
Na przykład:
- Atmel ATMEGA32U2 (2010):
TIFR1
(zamiastTimerCounter1InterruptFlag
),ICR1H
(zamiastInputCapture1High
),DDRB
(zamiastDataDirectionPortB
), etc. - Zestaw instrukcji .NET CLR (2002):
bge.s
(zamiastbranch-if-greater-or-equal.short
) itp.
Czy dłuższe, nieszyfrowane nazwy nie są łatwiejsze w obsłudze?
Odpowiadając i głosując, weź pod uwagę następujące kwestie. Wiele sugerowanych tutaj możliwych wyjaśnień odnosi się w równym stopniu do programowania na wysokim poziomie, a jednak ogólnie rzecz biorąc konsensus polega na użyciu nieszyfrowych nazw składających się ze słowa lub dwóch (z wyłączeniem powszechnie rozumianych akronimów).
Ponadto, jeśli twój główny argument dotyczy fizycznej przestrzeni na papierowym diagramie , należy wziąć pod uwagę, że absolutnie nie dotyczy to asemblera lub CIL, a ponadto byłbym wdzięczny, jeśli pokażesz mi diagram, w którym krótkie nazwy pasują, ale czytelne, pogarszają diagram . Z osobistego doświadczenia w bezkonkurencyjnej firmie zajmującej się półprzewodnikami, czytelne nazwy pasują dobrze i dają czytelniejsze diagramy.
Jaka jest podstawowa rzecz, która różni się w programowaniu niskiego poziomu w porównaniu do języków wysokiego poziomu, co sprawia, że zwięzłe, tajemnicze nazwy są pożądane w programowaniu niskiego poziomu, ale nie w programach wysokiego poziomu?
źródło
JSR
jest trzy razy dłuższy niż reprezentowany przez niego kod operacji ($20
w 6502) i znacznie łatwiejszy do zrozumienia na pierwszy rzut oka.set Accumulator32 to BaseIndex32
? Po prostu rozszerzenie tradycyjnych skrótów nie jest jedynym sposobem na uczynienie czegoś bardziej czytelnym.Odpowiedzi:
Oprogramowanie korzysta z tych nazw, ponieważ arkusze danych używają tych nazw. Ponieważ kod na tym poziomie jest bardzo trudny do zrozumienia bez arkusza danych, tworzenie nazw zmiennych, których nie można wyszukiwać, jest wyjątkowo nieprzydatne.
To rodzi pytanie, dlaczego arkusze danych używają krótkich nazw. Prawdopodobnie dlatego, że często musisz przedstawiać nazwy w tabelach takich jak ta, w których nie ma miejsca na identyfikatory o długości 25 znaków:
Ponadto, takie jak schematy, schematy pinów i sitodruki PCB często są bardzo ciasne dla przestrzeni.
źródło
Prawo Zipfa
Patrząc na ten tekst, możesz sam zaobserwować, że długość słowa i częstotliwość użycia są na ogół odwrotnie powiązane. Słowa, które są używane bardzo często, jak
it
,a
,but
,you
, iand
są bardzo krótkie, a słowa, które są rzadziej używane podobaobserve
,comprehension
iverbosity
są dłuższe. Ten zaobserwowany związek między częstotliwością a długością nazywa się prawem Zipfa .Liczba instrukcji w zestawie instrukcji dla danego mikroprocesora zwykle jest liczona w dziesiątkach lub setkach. Na przykład zestaw instrukcji Atmel AVR wydaje się zawierać około stu różnych instrukcji (nie liczyłem), ale wiele z nich jest odmianą wspólnego tematu i ma bardzo podobne mnemoniki. Na przykład instrukcje mnożenia obejmują MUL, MULS, MULSU, FMUL, FMULS i FMULSU. Nie musisz długo patrzeć na listę instrukcji, zanim zrozumiesz, że instrukcje rozpoczynające się od „BR” to rozgałęzienia, instrukcje rozpoczynające się od „LD” to obciążenia itp. To samo dotyczy zmiennych: nawet skomplikowane procesory zapewniają tylko ograniczoną liczbę miejsc do przechowywania wartości: rejestry stanu, rejestry ogólnego przeznaczenia itp.
Ponieważ instrukcji jest tak mało, a długie nazwy wymagają więcej czasu, warto nadać im krótkie nazwy. Z kolei języki wyższego poziomu pozwalają programistom tworzyć ogromną liczbę funkcji, metod, klas, zmiennych i tak dalej. Każda z nich będzie używana znacznie rzadziej niż większość instrukcji asemblacyjnych, a dłuższe, bardziej opisowe nazwy są coraz ważniejsze, aby dać czytelnikom (i pisarzom) wystarczającą ilość informacji, aby zrozumieć, czym są i co robią.
Ponadto zestawy instrukcji dla różnych procesorów często używają podobnych nazw dla podobnych operacji. Większość zestawów instrukcji obejmuje operacje na ADD, MUL, SUB, LD, ST, BR, NOP, a jeśli nie używają tych dokładnych nazw, zwykle używają nazw bardzo bliskich. Gdy nauczysz się mnemoniki dla jednego zestawu instrukcji, dostosowanie się do zestawów instrukcji dla innych urządzeń nie trwa długo. Więc może się wydawać, że nazwy „tajemnicze” do ciebie są tak znajome jak słowa takie jak
and
,or
inot
dla programistów, którzy są biegli w sztuce programowania niskiego poziomu. Myślę, że większość osób pracujących na poziomie asemblera powiedziałaby ci, że nauka czytania kodu nie jest jednym z większych wyzwań w programowaniu na niskim poziomie.źródło
Ogólnie
Jakość nazewnictwa to nie tylko posiadanie nazw opisowych, ale także inne aspekty, a to prowadzi do rekomendacji takich jak:
Pamiętaj, że te zalecenia są sprzeczne.
Instrukcja mnemoniki
Jako programista w asemblerze używanie
short-branch-if-greater-or-equal
forbge.s
daje mi takie samo wrażenie, jak kiedy widzę, jako programista AlgolSUBSTRACT THE-HORIZONTAL-COORDINATE-OF-THE-FIRST-POINT TO THE-HORIZONTAL-COORDINATE-OF-THE-SECOND-POINT GIVING THE-DIFFERENCES-OF-THE-COORDINATE-OF-THE-TWO-POINTS
zamiast geometrii obliczeniowejdx := p2.x - p1.x
. Po prostu nie mogę się zgodzić, że te pierwsze są bardziej czytelne w kontekście, na którym mi zależy.Zarejestruj nazwy
Wybierz oficjalną nazwę z dokumentacji. Dokumentacja wybiera nazwę z projektu. Projekt wykorzystuje wiele formatów graficznych, w których długie nazwy nie są odpowiednie, a zespół projektowy będzie żył z tymi nazwami przez miesiące, jeśli nie lata. Z obu powodów nie będą używać „flagi Przerwania pierwszego licznika timera”, będą skracać ją w swoim schemacie, a także podczas mówienia. Wiedzą o tym i używają systematycznych skrótów,
TIFR1
aby zmniejszyć ryzyko pomyłki. Jednym z punktów jest to, żeTIFR1
nie jest to przypadkowy skrót, to wynik schematu nazewnictwa.źródło
TIFR1
naprawdę jest lepszy schemat nazewnictwa niż tenInterruptFlag1
, czyIptFlag1
naprawdę musisz być krótki?InterruptFlag
iIptFlag
są lepsze niżIF
w ten sam sposóbEnumerableInterface
iItfcEnumerable
są lepsze niżIEnumerable
.InterruptFlag1
ze względu na lepszą przejrzystość.Oprócz powodów „starych nawyków”, starszy kod, który został napisany 30 lat temu i jest nadal w użyciu, jest bardzo powszechny. Pomimo tego, co myślą niektórzy mniej doświadczeni ludzie, refaktoryzacja tych systemów, aby wyglądały ładnie, wiąże się z bardzo wysokimi kosztami przy niewielkim zysku i nie jest opłacalna ekonomicznie.
Systemy osadzone, które są blisko sprzętu - i uzyskują dostęp do rejestrów, zwykle używają takich samych lub podobnych etykiet jak te używane w arkuszach danych sprzętu, z bardzo dobrych powodów. Jeśli rejestr nazywa się XYZZY1 w arkuszach danych sprzętu, sensowna jest, że zmienna reprezentująca go to XYZZY1, lub jeśli programista miał dobry dzień, RegXYZZY1.
Jeśli chodzi o to
bge.s
, jest podobny do asemblera - dla niewielu osób, które muszą to wiedzieć, dłuższe nazwy są mniej czytelne. Jeśli nie możesz się oderwać od siebiebge.s
i myśliszbranch-if-greater-or-equal.short
, że coś zmieni - grasz tylko CLR i nie wiesz o tym.Innym powodem, dla którego zobaczysz krótkie nazwy zmiennych, jest szerokie rozpowszechnienie skrótów w domenie, na którą program jest kierowany.
Podsumowując - spodziewane są krótkie skrócone nazwy zmiennych odzwierciedlające wpływ zewnętrzny, takie jak normy branżowe i karty danych sprzętu. Krótkie skrócone nazwy zmiennych, które są wewnętrzne dla oprogramowania, są zwykle mniej pożądane.
źródło
TIFR1
jest bardziej czytelny dla tych, którzy go potrzebująTimerCounter1InterruptFlag
, prawda?j?
instrukcje . Posiadanie bardziej oczywistej nazwy instrukcji zdecydowanie by mi pomogło. Ale może jestem raczej wyjątkiem niż regułą. Mam problem z zapamiętaniem trywialnych szczegółów.Jest tutaj tak wiele różnych pomysłów. Nie mogę przyjąć żadnej z istniejących odpowiedzi jak na odpowiedź: po pierwsze, istnieje prawdopodobnie wiele czynników, które przyczyniają się do tego, a po drugie, nie może wiedzieć, który z nich jest najbardziej istotna.
Oto podsumowanie odpowiedzi zamieszczonych przez innych tutaj. Zamieszczam to jako CW i moim zamiarem jest ostatecznie oznaczenie go jako zaakceptowanego. Edytuj, jeśli coś przeoczyłem. Próbowałem przeformułować każdy pomysł, aby wyrazić go zwięźle, ale wyraźnie.
Dlaczego więc tajemnicze krótkie identyfikatory są tak powszechne w programowaniu niskiego poziomu?
branch-if-greater-than-or-equal.short
jest początkowo bardziej czytelny niżbge.s
, ale z pewną praktyką sytuacja się odwraca.Osobiście uważam, że niektóre z nich w rzeczywistości nie przyczyniają się do powodów, dla których nowo opracowany system wybrałby ten styl nazewnictwa, ale uważam, że błędem byłoby odfiltrowywanie niektórych pomysłów w odpowiedzi tego typu.
źródło
Wrzucę kapelusz w ten bałagan.
Konwencje i standardy kodowania wysokiego poziomu to nie to samo, co standardy i praktyki kodowania niskiego poziomu. Niestety większość z nich to pozostałości po starym kodzie i starych procesach myślowych.
Niektóre jednak służą celowi. Na pewno BranchGreaterThan byłby znacznie bardziej czytelny niż BGT , ale teraz istnieje konwencja, jest to instrukcja i jako taka zyskała trochę przyczepności w ciągu ostatnich 30 lat użytkowania jako standard. Dlaczego zaczęli od tego, prawdopodobnie jakiś limit szerokości znaków dla instrukcji, zmiennych i tym podobnych; dlaczego go trzymają, to standard. Ten standard jest taki sam, jak użycie int jako identyfikatora, użycie liczb całkowitych byłoby bardziej czytelne we wszystkich przypadkach, ale jest konieczne dla każdego, kto programuje dłużej niż kilka tygodni ... nie. Dlaczego? Ponieważ to standardowa praktyka.
Po drugie, jak powiedziałem w moim komentarzu, wiele przerwań nosi nazwę INTG1 i inne tajemnicze nazwy, które również służą celowi. Na schematach obwodów NIE jest dobrą konwencją nazywanie twoich linii, a tak obszernie zaśmieca schemat i szkodzi czytelności. Wszelka gadatliwość jest opisana w dokumentacji. A ponieważ wszystkie schematy połączeń / obwodów mają te krótkie nazwy linii przerwań, same przerwania również mają taką samą nazwę, aby zachować spójność dla projektanta osadzonego ze schematu obwodu aż do kodu, aby go zaprogramować.
Projektant ma nad tym pewną kontrolę, ale podobnie jak każdy inny język / nowy język, istnieją konwencje, które następują od sprzętu do sprzętu i jako takie powinny pozostać podobne w każdym języku asemblera. Mogę spojrzeć na fragment asemblera i być w stanie uzyskać treść kodu bez użycia tego zestawu instrukcji, ponieważ trzymają się konwencji, LDA lub jakiegoś związku z nią prawdopodobnie ładuje rejestr MV prawdopodobnie coś przenosi gdzieś gdzie indziej nie chodzi o to, co uważasz za przyjemne lub o praktykę na wysokim poziomie, jest to język sam w sobie i jako taki ma swoje własne standardy i oznacza, że jako projektant powinien podążać, często nie są one tak arbitralne jak wydają się.
Zostawię cię z tym: Poproszenie społeczności osadzonej o stosowanie pełnych praktyk wysokiego poziomu jest jak proszenie chemików, aby zawsze zapisywali związki chemiczne. Chemik pisze je dla siebie i każdy w tej dziedzinie to zrozumie, ale dostosowanie się może zająć nowemu przybyszowi trochę czasu.
źródło
Jednym z powodów, dla których używają tajemniczych krótkich identyfikatorów, jest to, że nie są one tajemnicze dla programistów. Musisz zdać sobie sprawę, że pracują z tym na co dzień, a te nazwy są naprawdę nazwami domen. Więc wiedzą na pamięć, co dokładnie oznacza TIFR1.
Jeśli nowy zespół przyjdzie do zespołu, będzie musiał przeczytać arkusze danych (jak wyjaśniono w @KarlBielefeldt), aby mogli się z nimi swobodnie zapoznać.
Sądzę, że twoje pytanie posłużyło za zły przykład, ponieważ rzeczywiście na tego rodzaju kodach źródłowych zwykle widzisz wiele niepotrzebnych identyfikatorów krypt dla rzeczy spoza domeny.
Powiedziałbym, że robią to głównie z powodu złych nawyków, które istniały, gdy kompilatory nie uzupełniały automatycznie wszystkiego, co piszesz.
źródło
Podsumowanie
Inicjalizm jest zjawiskiem wszechobecnym w wielu kręgach technicznych i nietechnicznych. Jako taki nie ogranicza się do programowania niskiego poziomu. Ogólną dyskusję można znaleźć w artykule na temat akronimu w Wikipedii . Moja odpowiedź dotyczy programowania niskopoziomowego.
Przyczyny tajemniczych nazw:
Rozwiązania i ich wady:
Pełna odpowiedź
(A) Możliwe są dłuższe nazwy. Na przykład nazwy wewnętrzne C ++ SSE2 mają średnio 12 znaków w porównaniu do 7 znaków w mnemoniku zestawu. http://msdn.microsoft.com/en-us/library/c8c5hx3b(v=vs.80).aspx
(B) Następnie pojawia się pytanie: jak długo / nieszyfrowane trzeba uzyskać z instrukcji niskiego poziomu?
(C) Teraz analizujemy skład takich schematów nazewnictwa. Oto dwa schematy nazewnictwa dla tej samej instrukcji niskiego poziomu:
CVTSI2SD
__m128d _mm_cvtsi32_sd (__m128d a, int b);
(C.1) Instrukcje niskiego poziomu są zawsze silnie napisane. Nie może być dwuznaczności, wnioskowania o typie, automatycznej konwersji typu ani przeciążenia (ponowne użycie nazwy instrukcji w celu oznaczenia podobnych, ale nie równoważnych operacji).
(C.2) Każda instrukcja niskiego poziomu musi zawierać w swojej nazwie wiele informacji typu. Przykłady informacji:
(C.3) Jeśli każda informacja zostanie przeliterowana, program będzie bardziej szczegółowy.
(C.4) Schematy kodowania typów stosowane przez różnych dostawców mają długie historyczne korzenie. Na przykład w zestawie instrukcji x86:
Te odniesienia historyczne nie miały żadnego współczesnego znaczenia, ale wciąż się utrzymują. Bardziej spójny schemat umieściłby w nazwie wartość szerokości bitu (8, 16, 32, 64, 128).
Przeciwnie, LLVM jest właściwym krokiem w kierunku spójności instrukcji niskiego poziomu: http://llvm.org/docs/LangRef.html#functions
(D) Niezależnie od schematu nazewnictwa instrukcji, programy niskiego poziomu są już pełne i trudne do zrozumienia, ponieważ koncentrują się na najdrobniejszych szczegółach wykonania. Zmiana schematu nazewnictwa instrukcji poprawi czytelność na poziomie linia-linia, ale nie usunie trudności w zrozumieniu operacji dużego fragmentu kodu.
źródło
CVTSI2SD
nie wykonuje żadnych więcej informacji niżConvertDword2Double
alboConvInt32ToFloat64
, ale te ostatnie, podczas gdy dłużej, są natychmiast rozpoznawalne, podczas gdy pierwsza musi być rozszyfrowane ...Ludzie od czasu do czasu czytają i piszą asemblery, a przez większość czasu jest to tylko protokół komunikacyjny. Tj. Jest najczęściej używany jako pośrednia serializowana reprezentacja tekstowa między kompilatorem a asemblerem. Im bardziej szczegółowa jest ta reprezentacja, tym bardziej niepotrzebny jest narzut w tym protokole.
W przypadku kodów opc i nazw rejestrów długie nazwy w rzeczywistości szkodzą czytelności. Krótkie mnemoniki są lepsze dla protokołu komunikacyjnego (między kompilatorem a asemberem), a język asemblera jest przez większość czasu protokołem komunikacyjnym. Krótkie mnemoniki są lepsze dla programistów, ponieważ kod kompilatora jest łatwiejszy do odczytania.
źródło
TIFR
, czy też zawierają one pełne słowa?Przeważnie jest to idiomatyczne. Jak napisano w innym miejscu @TMN, tak jak nie piszesz
import JavaScriptObjectNotation
aniimport HypertextTransferProtocolLibrary
w Pythonie, nie piszeszTimer1LowerHalf = 0xFFFF
w C. Wygląda równie śmiesznie w kontekście. Każdy, kto musi wiedzieć, już wie.Odporność na zmiany może wynikać częściowo z faktu, że niektórzy dostawcy kompilatorów C dla systemów wbudowanych odbiegają od standardu językowego i składni w celu implementacji funkcji bardziej przydatnych dla programowania wbudowanego. Oznacza to, że nie zawsze możesz używać funkcji autouzupełniania swojego ulubionego IDE lub edytora tekstowego podczas pisania kodu niskiego poziomu, ponieważ dostosowania te osłabiają ich zdolność do analizowania kodu. Stąd użyteczność krótkich nazw rejestrów, makr i stałych.
Na przykład kompilator C HiTech zawiera specjalną składnię dla zmiennych, które musiały mieć w pamięci określoną przez użytkownika pozycję. Możesz zadeklarować:
Teraz jedynym istniejącym IDE, które będzie analizowało to IDE HiTech ( HiTide ). W każdym innym edytorze musisz za każdym razem wpisywać go ręcznie z pamięci. Starzeje się bardzo szybko.
Jest też fakt, że kiedy używasz narzędzi programistycznych do sprawdzania rejestrów, często wyświetlasz tabelę z kilkoma kolumnami (nazwa rejestru, wartość szesnastkowa, wartość dwójkowa, ostatnia wartość szesnastkowa itp.). Długie nazwy oznaczają, że musisz rozwinąć kolumnę nazwy do 13 znaków, aby zobaczyć różnicę między dwoma rejestrami, i grać „zauważ różnicę” w dziesiątkach wierszy powtarzanych słów.
Może to zabrzmieć jak głupie drobiazgi, ale czy nie każda konwencja kodowania ma na celu zmniejszenie zmęczenia oczu, zmniejszenie zbędnego pisania lub rozwiązanie jednej z milionów innych drobnych skarg?
źródło
File.ReadAllBytes
może też wyglądać absurdalnie długo dla kogoś, kto był do tego przyzwyczajonyfread
. Więc ... po co inaczej traktować kod wysokiego i niskiego poziomu ?Timer1InterruptFlag
,Timer2InterruptFlag
, ...,Timer9InterruptFlag
,IOPortAToggleMask
,IOPortBToggleMask
, etc x100. W języku wyższego poziomu użyłbyś zmiennych, które różnią się znacznie bardziej ... lub użyłbyś większej struktury.Timer1InterruptFlag
to 75% nieistotnego hałasu w porównaniu doT1IF
. Nie sądzę, żebyś stworzył ogromną listę zmiennych w C #, które ledwo się tak różnią.UARTEnable(UART1, BITS_8, PARITY_N, STOP_1, BAUD_115200)
. Ale wciąż są niesamowicie niezgrabne i wymagają dużo pośredniej i nieefektywnej pracy. Staram się ich używać tam, gdzie to możliwe, ale w większości przypadków manipuluję rejestrem we własnych funkcjach i wywołuję go z logiki wyższego poziomu.set_prescalar(TMR4,13);
jest IMHO o wiele mniej jasne niż byłobyTMR4->PSREG=12;
. Nawet jeśli spojrzysz na instrukcję kompilatora, aby dowiedzieć się, co robi pierwszy kod, prawdopodobnie nadal będziesz musiał ...Dziwi mnie, że nikt nie wspominał o lenistwie i że inne nauki nie są omawiane. Moja codzienna praca jako programista pokazuje mi, że na konwencje nazewnictwa dla dowolnej zmiennej w programie mają wpływ trzy różne aspekty:
Myślę, że nie ma sensu dyskutować o programowaniu na niskim lub wysokim poziomie. Na samym końcu zawsze można go przypisać do trzech poprzednich aspektów.
Wyjaśnienie pierwszego aspektu: Wielu „programistów” nie jest programistami. Są matematykami, fizykami, biologami, a nawet psychologami lub ekonomistami, ale wielu z nich nie jest informatykami. Większość z nich ma własne słowa kluczowe i skróty, które można zobaczyć w ich „konwencjach” nazewnictwa. Często są uwięzieni w swojej dziedzinie i używają znanych skrótów, nie myśląc o instrukcjach dotyczących czytelności ani kodowania.
Wyjaśnienie drugiego aspektu: ponieważ większość programistów nie jest informatykami, ich umiejętności programowania są ograniczone. Dlatego często nie dbają o konwencje kodowania, ale bardziej o konwencje specyficzne dla domeny, jak podano jako pierwszy aspekt. Również jeśli nie masz umiejętności programisty, nie rozumiesz konwencji kodowania. Myślę, że większość z nich nie widzi pilnej potrzeby napisania zrozumiałego kodu. To jak ogień i zapomnieć.
Wyjaśnienie trzeciego aspektu: jest mało prawdopodobne, aby hamować konwencje twojego środowiska, które mogą być starym kodem, który musisz obsługiwać, standardami kodowania twojej firmy (prowadzonymi przez ekonomistów, którzy nie dbają o kodowanie) lub domeną, do której należysz. Jeśli ktoś zaczął używać tajemniczych nazw, a ty musisz wesprzeć go lub jego kod, jest mało prawdopodobne, aby zmienić tajemnicze nazwy. Jeśli w twojej firmie nie ma standardów kodowania, założę się, że prawie każdy programista napisze własny standard. I na koniec, jeśli jesteś otoczony przez użytkowników domeny, nie zaczniesz pisać innego języka niż oni używają.
źródło