C veri türleri "çoğu bilgisayar tarafından doğrudan desteklenir"?


114

K & R'nin "C Programlama Dili" ni okuyorum ve bu ifadeyle karşılaştım [Giriş, s. 3]:

C tarafından sağlanan veri türleri ve denetim yapıları çoğu bilgisayar tarafından doğrudan desteklendiğinden , bağımsız programları uygulamak için gereken çalışma zamanı kitaplığı çok küçüktür.

Kalın yazılmış ifade ne anlama geliyor? Bir veri türü veya bir kontrol yapısının bir örneği var olmayan bir bilgisayar tarafından desteklenen?


1
Bu günlerde, C dili karmaşık aritmetiği destekliyor, ancak başlangıçta bu desteklemiyordu çünkü bilgisayarlar veri türleri olarak karmaşık sayıları doğrudan desteklemiyor.
Jonathan Leffler

12
Aslında, tarihsel olarak tam tersi bir durumdu: C, o sırada mevcut olan donanım işlemleri ve türlerinden tasarlandı.
Basile Starynkevitch

2
Çoğu bilgisayarda ondalık yüzer
sayılar

3
@MSalters: "Bir bilgisayar tarafından doğrudan desteklenmeyen bir veri tipi veya kontrol yapısı örneği var mı?" Sorusu için bir ipucu vermeye çalışıyordum. K&R
PlasmaHH

11
Stack Overflow başlatıldıktan sonra 6 yıldan fazla bir süre sonra bu nasıl bir kopya olmaz?
Peter Mortensen

Yanıtlar:


143

Evet, doğrudan desteklenmeyen veri türleri vardır.

Birçok gömülü sistemde donanım kayan nokta birimi yoktur. Öyleyse, böyle bir kod yazdığınızda:

float x = 1.0f, y = 2.0f;
return x + y;

Bunun gibi bir şeye çevrilir:

unsigned x = 0x3f800000, y = 0x40000000;
return _float_add(x, y);

Daha sonra derleyici veya standart kitaplık, _float_add()gömülü sisteminizde belleği kaplayan bir uygulama sağlamalıdır . Baytları gerçekten küçük bir sistemde sayıyorsanız, bu artabilir.

Diğer bir yaygın örnek, long long32 bit sistemler tarafından doğrudan desteklenmeyen 64 bitlik tam sayılardır ( 1999'dan beri C standardında). Eski SPARC sistemleri tamsayı çarpmayı desteklemiyordu, bu nedenle çarpma işleminin çalışma zamanı tarafından sağlanması gerekiyordu. Başka örnekler de var.

Diğer diller

Karşılaştırıldığında, diğer dillerin daha karmaşık ilkelleri vardır.

Örneğin, bir Lisp sembolü, Lua'daki tablolar, Python'daki dizeler, Fortran'daki diziler vb. Gibi çok sayıda çalışma zamanı desteği gerektirir. C'deki eşdeğer türler genellikle ya standart kitaplığın bir parçası değildir (standart semboller veya tablolar yoktur) ya da çok daha basittirler ve çok fazla çalışma zamanı desteği gerektirmezler (C'deki diziler temelde sadece işaretçilerdir, sıfır sonlu dizeler neredeyse kadar basit).

Kontrol Yapıları

C'de eksik olan dikkate değer bir kontrol yapısı, istisna işlemedir. Yerel olmayan çıkış, yalnızca işlemci durumunun belirli bölümlerini kaydedip geri yükleyen setjmp()ve ile sınırlıdır longjmp(). Buna karşılık, C ++ çalışma zamanının yığını yürütmesi ve yıkıcıları ve özel durum işleyicileri çağırması gerekir.


2
temelde sadece işaretçiler ... daha ziyade, temelde sadece ham bellek parçaları. İşin özü bu olsa bile ve cevap yine de iyi.
Tekilleştirici

2
Boş sonlandırılmış dizelerin "donanım desteğine" sahip olduğunu, dize sonlandırıcısının çoğu işlemcinin "sıfırsa atla" işlemine uyduğunu ve dolayısıyla diğer olası dizge uygulamalarından biraz daha hızlı olduğunu iddia edebilirsiniz.
Peteris

1
C'nin basitçe asm ile eşlemek için nasıl tasarlandığını genişletmek için kendi cevabımı yayınladım.
Peter Cordes

1
Lütfen eşdizimi kullanmayın "diziler temelde sadece işaretçilerdir", bu, OP gibi yeni başlayanları ciddi ve kötü bir şekilde yanıltabilir. "Diziler, donanım düzeyinde işaretçiler kullanılarak doğrudan uygulanır" satırları boyunca bir şey daha iyi IMO olacaktır.
The Paramagnetic Kruvasan

1
@TheParamagneticCroissant: Bu bağlamda uygun olduğunu düşünüyorum ... netlik, hassasiyet pahasına gelir.
Dietrich Epp

37

Aslında, bu girişin içeriğinin Kernighan ve Ritchie'nin kitabın Birinci Baskı'da ilk kez yazdıkları 1978'den beri pek değişmediğine ve C'nin o zamanki tarihine ve evrimine modernden daha çok atıfta bulunduğuna bahse girerim. uygulamalar.

Bilgisayarlar temelde sadece bellek bankaları ve merkezi işlemcilerdir ve her işlemci bir makine kodu kullanarak çalışır; Her işlemcinin tasarımının bir parçası, bir komut kümesi mimarisidir. bir dizi insan tarafından okunabilir anımsatıcıdan tümü sayılardan oluşan makine koduna bire bir eşleyen Assembly Dili .

C dilinin yazarları - ve ondan hemen önce gelen B ve BCPL dilleri - mümkün olduğunca verimli bir şekilde Assembly'de derlenen yapıları tanımlamaya niyetliydi ... aslında, hedefteki sınırlamalar nedeniyle zorlandılar. donanım. Diğer yanıtların da belirttiği gibi, bu dallar (GOTO ve C'deki diğer akış kontrolü), hareketler (atama), mantıksal işlemler (& | ^), temel aritmetik (toplama, çıkarma, artırma, azaltma) ve bellek adresleme (işaretçiler ). İyi bir örnek, C'deki ön / son artırma ve azaltma operatörleri olup, Ken Thompson tarafından özellikle derlendikten sonra doğrudan tek bir işlem koduna çeviri yapabildikleri için B diline eklenmişlerdir.

Yazarların "çoğu bilgisayar tarafından doğrudan desteklenir" derken kastettiği buydu. Onlar bu diğer diller edildi türleri ve yapıları içerdiği anlamına gelmiyordu değil doğrudan destekli - onlar anlamına geliyordu tarafından dizayn C yapılar tercüme en (bazen doğrudan anlamıyla Kurul doğrudan).

Yapılandırılmış programlama için gerekli tüm unsurları sağlamaya devam ederken, temeldeki Meclis ile olan bu yakın ilişki, C'nin erken benimsenmesine yol açan ve onu derlenen kodun verimliliğinin hala anahtar olduğu ortamlarda bugün popüler bir dil yapan şeydir.

Dil tarihi hakkında ilginç bir yazı için bkz.C Dilinin Gelişimi - Dennis Ritchie


14

Kısa cevap, C tarafından desteklenen dil yapılarının çoğu aynı zamanda hedef bilgisayarın mikro işlemcisi tarafından da desteklenmektedir, bu nedenle derlenmiş C kodu mikroişlemcinin montaj diline çok güzel ve verimli bir şekilde çevrilir ve böylece daha küçük kod ve daha küçük bir ayak izi ile sonuçlanır.

Daha uzun cevap, biraz derleme dili bilgisi gerektirir. C'de şöyle bir ifade:

int myInt = 10;

montajda böyle bir şeye çevrilir:

myInt dw 1
mov myInt,10

Bunu C ++ gibi bir şeyle karşılaştırın:

MyClass myClass;
myClass.set_myInt(10);

Elde edilen derleme dili kodu (MyClass () değerinin ne kadar büyük olduğuna bağlı olarak), yüzlerce derleme dili satırı ekleyebilir.

Aslında assembly dilinde programlar oluşturmadan, saf C muhtemelen içinde bir program yapabileceğiniz "en ince" ve "en sıkı" koddur.

DÜZENLE

Cevabımla ilgili yorumlar göz önüne alındığında, sadece kendi akıl sağlığım için bir test yapmaya karar verdim. "Test.c" adlı bir program oluşturdum, şuna benzer:

#include <stdio.h>

void main()
{
    int myInt=10;

    printf("%d\n", myInt);
}

Bunu gcc kullanarak derlemeye kadar derledim. Derlemek için aşağıdaki komut satırını kullandım:

gcc -S -O2 test.c

İşte ortaya çıkan montaj dili:

    .file   "test.c"
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC0:
    .string "%d\n"
    .section    .text.unlikely,"ax",@progbits
.LCOLDB1:
    .section    .text.startup,"ax",@progbits
.LHOTB1:
    .p2align 4,,15
    .globl  main
    .type   main, @function
main:
.LFB24:
    .cfi_startproc
    movl    $10, %edx
    movl    $.LC0, %esi
    movl    $1, %edi
    xorl    %eax, %eax
    jmp __printf_chk
    .cfi_endproc
.LFE24:
    .size   main, .-main
    .section    .text.unlikely
.LCOLDE1:
    .section    .text.startup
.LHOTE1:
    .ident  "GCC: (Ubuntu 4.9.1-16ubuntu6) 4.9.1"
    .section    .note.GNU-stack,"",@progbits

Daha sonra bir sınıfı tanımlayan ve "test.c" ile aynı şeyi veren "test.cpp" adlı bir dosya oluşturuyorum:

#include <iostream>
using namespace std;

class MyClass {
    int myVar;
public:
    void set_myVar(int);
    int get_myVar(void);
};

void MyClass::set_myVar(int val)
{
    myVar = val;
}

int MyClass::get_myVar(void)
{
    return myVar;
}

int main()
{
    MyClass myClass;
    myClass.set_myVar(10);

    cout << myClass.get_myVar() << endl;

    return 0;
}

Bu komutu kullanarak aynı şekilde derledim:

g++ -O2 -S test.cpp

İşte ortaya çıkan montaj dosyası:

    .file   "test.cpp"
    .section    .text.unlikely,"ax",@progbits
    .align 2
.LCOLDB0:
    .text
.LHOTB0:
    .align 2
    .p2align 4,,15
    .globl  _ZN7MyClass9set_myVarEi
    .type   _ZN7MyClass9set_myVarEi, @function
_ZN7MyClass9set_myVarEi:
.LFB1047:
    .cfi_startproc
    movl    %esi, (%rdi)
    ret
    .cfi_endproc
.LFE1047:
    .size   _ZN7MyClass9set_myVarEi, .-_ZN7MyClass9set_myVarEi
    .section    .text.unlikely
.LCOLDE0:
    .text
.LHOTE0:
    .section    .text.unlikely
    .align 2
.LCOLDB1:
    .text
.LHOTB1:
    .align 2
    .p2align 4,,15
    .globl  _ZN7MyClass9get_myVarEv
    .type   _ZN7MyClass9get_myVarEv, @function
_ZN7MyClass9get_myVarEv:
.LFB1048:
    .cfi_startproc
    movl    (%rdi), %eax
    ret
    .cfi_endproc
.LFE1048:
    .size   _ZN7MyClass9get_myVarEv, .-_ZN7MyClass9get_myVarEv
    .section    .text.unlikely
.LCOLDE1:
    .text
.LHOTE1:
    .section    .text.unlikely
.LCOLDB2:
    .section    .text.startup,"ax",@progbits
.LHOTB2:
    .p2align 4,,15
    .globl  main
    .type   main, @function
main:
.LFB1049:
    .cfi_startproc
    subq    $8, %rsp
    .cfi_def_cfa_offset 16
    movl    $10, %esi
    movl    $_ZSt4cout, %edi
    call    _ZNSolsEi
    movq    %rax, %rdi
    call    _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
    xorl    %eax, %eax
    addq    $8, %rsp
    .cfi_def_cfa_offset 8
    ret
    .cfi_endproc
.LFE1049:
    .size   main, .-main
    .section    .text.unlikely
.LCOLDE2:
    .section    .text.startup
.LHOTE2:
    .section    .text.unlikely
.LCOLDB3:
    .section    .text.startup
.LHOTB3:
    .p2align 4,,15
    .type   _GLOBAL__sub_I__ZN7MyClass9set_myVarEi, @function
_GLOBAL__sub_I__ZN7MyClass9set_myVarEi:
.LFB1056:
    .cfi_startproc
    subq    $8, %rsp
    .cfi_def_cfa_offset 16
    movl    $_ZStL8__ioinit, %edi
    call    _ZNSt8ios_base4InitC1Ev
    movl    $__dso_handle, %edx
    movl    $_ZStL8__ioinit, %esi
    movl    $_ZNSt8ios_base4InitD1Ev, %edi
    addq    $8, %rsp
    .cfi_def_cfa_offset 8
    jmp __cxa_atexit
    .cfi_endproc
.LFE1056:
    .size   _GLOBAL__sub_I__ZN7MyClass9set_myVarEi, .-_GLOBAL__sub_I__ZN7MyClass9set_myVarEi
    .section    .text.unlikely
.LCOLDE3:
    .section    .text.startup
.LHOTE3:
    .section    .init_array,"aw"
    .align 8
    .quad   _GLOBAL__sub_I__ZN7MyClass9set_myVarEi
    .local  _ZStL8__ioinit
    .comm   _ZStL8__ioinit,1,1
    .hidden __dso_handle
    .ident  "GCC: (Ubuntu 4.9.1-16ubuntu6) 4.9.1"
    .section    .note.GNU-stack,"",@progbits

Açıkça görebileceğiniz gibi, ortaya çıkan montaj dosyası C ++ dosyasında çok daha büyüktür, ardından C dosyasındadır. Tüm diğer şeyleri kesip sadece C "ana" ı C ++ "ana" ile karşılaştırsanız bile, fazladan birçok şey vardır.


14
Bu "C ++ kodu" C ++ değildir. Ve MyClass myClass { 10 }C ++ 'daki gibi gerçek kodun tam olarak aynı derlemeye derlenmesi çok muhtemeldir. Modern C ++ derleyicileri, soyutlama cezasını ortadan kaldırdı. Ve sonuç olarak, genellikle C derleyicilerini yenebilirler. Örneğin, C'lerdeki soyutlama cezası qsortgerçektir, ancak C ++ 'ın std::sorttemel optimizasyondan sonra bile soyutlama cezası yoktur.
MSalters

1
IDA Pro'yu kullanarak, çoğu C ++ yapısının, bunu C'de elle yapmakla aynı şekilde derlediğini, kurucuların ve yönlendiricilerin önemsiz nesneler için sıraya dizildiğini ve daha sonra gelecekteki optimizasyonun uygulandığını
kolayca görebilirsiniz

7

K&R, çoğu C ifadesinin (teknik anlamı), bir destek kitaplığına bir işlev çağrısı değil, bir veya birkaç montaj talimatıyla eşleştiği anlamına gelir. Genel istisnalar, donanım div komutu olmayan mimarilerde tamsayı bölümü veya FPU'su olmayan makinelerde kayan noktadır.

Bir alıntı var:

C, assembly dilinin esnekliğini ve gücünü, assembly dilinin kullanım kolaylığıyla birleştirir.

( burada bulundu . "Assembly dilinin rahatlığı ve ifadesi ile montaj dili hızı" gibi farklı bir varyasyonu hatırladığımı düşündüm.)

long int genellikle yerel makine kayıtları ile aynı genişliktedir.

Bazı daha yüksek seviyeli diller, veri türlerinin tam genişliğini tanımlar ve tüm makinelerdeki uygulamalar aynı şekilde çalışmalıdır. Yine de C değil.

X86-64'te 128bit girişlerle veya genel durumda isteğe bağlı boyutta BigInteger ile çalışmak istiyorsanız, bunun için bir işlev kitaplığına ihtiyacınız vardır. Tüm CPU'lar artık negatif tam sayıların ikili temsili olarak 2s tamamlayıcı kullanıyor, ancak C tasarlandığında durum böyle değildi. (Bu nedenle 2s-tamamlayıcı olmayan makinelerde farklı sonuçlar verecek bazı şeyler teknik olarak C standartlarında tanımlanmamıştır.)

Verilere veya işlevlere yönelik C işaretçileri, derleme adresleriyle aynı şekilde çalışır.

Yeniden sayılmış referanslar istiyorsanız, bunu kendiniz yapmanız gerekir. İşaretçinizin işaret ettiği nesnenin türüne bağlı olarak farklı bir işlevi çağıran c ++ sanal üye işlevleri istiyorsanız, C ++ derleyicisinin yalnızca bircall sabit adresli talimattan .

Dizeler sadece dizilerdir

Kitaplık işlevlerinin dışında, sağlanan tek dize işlemleri bir karakter okuma / yazmadır. Concat yok, alt dize yok, arama yok. (Dizeler '\0'işaretçi + uzunluk değil, 8 bitlik tam sayılardan oluşan sıfır sonlu ( ) diziler olarak saklanır , bu nedenle bir alt dizeyi elde etmek için orijinal dizeye bir nul yazmanız gerekir.)

CPU'lar bazen bir dizi arama işlevi tarafından kullanılmak üzere tasarlanmış komutlara sahiptir, ancak yine de genellikle bir döngüde yürütülen komut başına bir bayt işler. (veya x86 rep önekiyle. Belki C x86 üzerinde tasarlandıysa, dize arama veya karşılaştırma bir kitaplık işlevi çağrısı yerine yerel bir işlem olabilir.)

Diğer birçok yanıt, istisna işleme, karma tablolar, listeler gibi yerel olarak desteklenmeyen şeylere örnekler verir. K & R'nin tasarım felsefesi, C'nin bunlardan hiçbirine yerel olarak sahip olmamasının sebebidir.


"K&R, çoğu C ifadesinin (teknik anlamı) bir destek kitaplığına bir işlev çağrısı değil, bir veya birkaç montaj talimatıyla eşleştiği anlamına gelir." Bu çok sezgisel bir açıklamadır. Teşekkürler.
gwg

1
Az önce "von Neumann dili" terimine rastladım ( en.wikipedia.org/wiki/Von_Neumann_programming_languages ). TAMAMEN C'nin ne olduğu.
Peter Cordes

1
İşte tam da bu yüzden C kullanıyorum. Ancak C'yi öğrenirken beni şaşırtan şey, geniş bir donanım yelpazesi için verimli olmaya çalışarak, bazen çoğu modern donanım üzerinde yetersiz ve verimsiz olmasıdır. Demek istediğim, örneğin , c'de tamsayı taşmasını tespit etmenin yararlı ve güvenilir olmayan yolu ve taşıma işaretini kullanarak birden çok sözcük ekleme .
Z bozonu

6

Bir sürecin montaj dili genellikle atlama (git), ifadeler, hareket ifadeleri, ikili artritik (XOR, NAND, AND OR, vb.), Bellek alanları (veya adres) ile ilgilidir. Belleği talimat ve veri olmak üzere iki türe sınıflandırır. Bu, tüm bir assembly dili ile ilgilidir (eminim assembly programcıları bundan daha fazlası olduğunu iddia edeceklerdir, ancak genel olarak bu kısaca özetlenir). C, bu sadeliğe çok benziyor.

C cebirin aritmetiğe göre ne olduğunu birleştirmektir.

C, montajın temellerini (işlemcinin dili) kapsüller. Muhtemelen "C tarafından sağlanan veri türleri ve kontrol yapıları çoğu bilgisayar tarafından doğrudan desteklendiği için" den daha doğru bir ifadedir.


5

Yanıltıcı karşılaştırmalara dikkat edin

  1. İfade, "çalışma zamanı kitaplığı" kavramına dayanır , en azından ana akım yüksek seviyeli diller için o zamandan beri çoğunlukla modası geçmiş olan . (En küçük gömülü sistemler için hala geçerlidir.) Çalışma zamanı, yalnızca dilde yerleşik yapıları kullandığınızda (bir kitaplık tarafından sağlanan bir işlevi açıkça çağırmanın aksine) o dildeki bir programın yürütmek için ihtiyaç duyduğu minimum destektir. .
  2. Buna karşılık, modern diller çalışma zamanı ile standart kitaplık arasında ayrım yapmama eğilimindedir. , ikincisi genellikle oldukça kapsamlıdır.
  3. K&R kitabı hazırlandığı sırada, C'nin standart bir kütüphanesi bile yoktu. . Aksine, mevcut C kitaplıkları, Unix'in farklı türleri arasında oldukça farklıydı.
  4. İfadeyi anlamak için standart bir kitaplığa sahip dillerle karşılaştırmamalısınız (diğer cevaplarda bahsedilen Lua ve Python gibi) değil, daha yerleşik yapılara sahip dillerle (eski LISP ve diğerlerinde belirtilen eski gün FORTRAN gibi) karşılaştırmalısınız. Yanıtlar). Diğer örnekler BASIC (interaktif, LISP gibi) veya PASCAL (FORTRAN gibi derlenmiş) olabilir, bunların her ikisi de (diğer şeylerin yanı sıra) doğrudan dilin içine yerleştirilmiş giriş / çıkış özelliklerine sahiptir.
  5. Buna karşılık, hesaplama sonuçlarını herhangi bir kitaplık değil, yalnızca çalışma zamanını kullanan bir C programından almanın standart bir yolu yoktur.

Öte yandan, çoğu modern dil, çöp toplama gibi olanaklar sağlayan özel çalışma zamanı ortamlarında çalışır.
Nate CK

5

Bir bilgisayar tarafından doğrudan desteklenmeyen bir veri türü veya kontrol yapısı örneği var mı?

Tüm temel veri türleri ve bunların C dilindeki işlemleri döngü olmadan bir veya birkaç makine dili talimatı ile uygulanabilir - bunlar (hemen hemen her) CPU tarafından doğrudan desteklenir.

Birkaç popüler veri türü ve işlemleri düzinelerce makine dili talimatı gerektirir veya bazı çalışma zamanı döngüsünün veya her ikisinin yinelenmesini gerektirir.

Birçok dilin bu türler ve işlemleri için özel kısaltılmış sözdizimi vardır - C'de bu tür veri türlerini kullanmak genellikle çok daha fazla kod yazmayı gerektirir.

Bu tür veri türleri ve işlemler şunları içerir:

  • arbiteryal uzunlukta metin dizesi işleme - birleştirme, alt dize, başka bir dizeyle başlatılmış bir değişkene yeni bir dize atama, vb. ('s = "Merhaba Dünya!"; s = (s + s) [2: -2] Python'da)
  • kümeler
  • C ++ ve diğer tüm nesne yönelimli programlama dillerinde olduğu gibi iç içe geçmiş sanal yıkıcılara sahip nesneler
  • 2D matris çarpımı ve bölme; doğrusal sistemleri çözme (MATLAB ve birçok dizi programlama dilinde "C = B / A; x = A \ b")
  • düzenli ifadeler
  • değişken uzunluklu diziler - özellikle, (bazen) daha fazla bellek ayırmayı gerektiren dizinin sonuna bir öğe eklemek.
  • çalışma zamanında türü değiştiren değişkenlerin değerini okumak - bazen bir kayan nokta, bazen de bir dizedir
  • ilişkilendirilebilir diziler (genellikle "haritalar" veya "sözlükler" olarak adlandırılır)
  • listeleri
  • oranlar ("(+ 1/3 2/7)", Lisp'te "13/21" değerini verir )
  • keyfi kesinlikte aritmetik (genellikle "bignum" olarak adlandırılır)
  • verileri yazdırılabilir bir temsile dönüştürme (JavaScript'teki ".tostring" yöntemi)
  • sabit noktalı sayıları doyurma (genellikle gömülü C programlarında kullanılır)
  • çalışma zamanında yazılan bir dizeyi bir ifadeymiş gibi değerlendirmek (birçok programlama dilinde "eval ()").

Tüm bu işlemler düzinelerce makine dili talimatı gerektirir veya neredeyse her işlemcide bir miktar çalışma zamanı döngüsünün yinelenmesini gerektirir.

Düzinelerce makine dili talimatı veya döngü gerektiren bazı popüler kontrol yapıları şunları içerir:

  • kapanışları
  • continuations
  • istisnalar
  • tembel değerlendirme

C veya başka bir dilde yazılmış olsun, bir program bu tür veri türlerini işlediğinde, CPU sonunda bu veri türlerini işlemek için gereken her türlü komutu yürütmelidir. Bu talimatlar genellikle bir "kitaplıkta" bulunur. Her programlama dili, hatta C, her bir yürütülebilir dosyaya varsayılan olarak dahil edilen her platform için bir "çalışma zamanı kitaplığına" sahiptir.

Derleyici yazan çoğu kişi, "dile dahil edilmiş" tüm veri türlerini işlemek için talimatları çalışma zamanı kitaplıklarına koyar. C olmadığı için herhangi bir eksantriklik daha C çalışma zamanı kitaplığı daha küçük hale getirir - dil, bunların hiçbiri C çalışma zamanı kütüphanesinde bulunur yerleşik yukarıdaki veri türleri ve operasyonlar ve kontrol yapılarının Yukarıdaki şeylerin çoğunun dilde yerleşik olduğu diğer programlama dillerinin zaman kitaplığı.

Bir programcı, bir programın (C veya seçtiği herhangi bir dilde) "dilde yerleşik" olmayan diğer veri türlerini işlemek için istediğinde, genellikle derleyiciye o programla ek kitaplıklar eklemesini söyler veya bazen ("bağımlılıkları önlemek için") bu işlemlerin başka bir uygulamasını doğrudan programa yazar.


Lisp uygulamanız (+ 1/3 2/7) 3/21 olarak değerlendirilirse, özellikle yaratıcı bir uygulamaya sahip olmanız gerektiğini düşünüyorum ...
RobertB

4

Yerleşik veri türleri Cnelerdir? Onlar gibi şeylerdir int, char, * int, float, diziler vs ... Bunlar veri türleri CPU tarafından anlaşılır. CPU dizilerle nasıl çalışılacağını, işaretçilerin nasıl kaldırılacağını ve işaretçiler, tam sayılar ve kayan nokta sayıları üzerinde aritmetik işlemlerin nasıl gerçekleştirileceğini bilir.

Ancak daha yüksek seviyeli programlama dillerine gittiğinizde soyut veri türleri ve daha karmaşık yapılar oluşturmuş olursunuz. Örneğin, C ++ programlama dilindeki geniş kapsamlı yerleşik sınıf dizisine bakın. CPU sınıfları, nesneleri veya soyut veri türlerini anlamaz, bu nedenle C ++ çalışma zamanı CPU ile dil arasındaki boşluğu kapatır. Bunlar, çoğu bilgisayar tarafından doğrudan desteklenmeyen veri türlerinin örnekleridir.


2
x86 bazı dizilerle çalışacağını bilir, ancak tümü ile değil. Büyük veya olağandışı eleman boyutları için, bir dizi indeksini bir işaretçi uzaklığına dönüştürmek için tamsayı aritmetiği gerçekleştirmesi gerekecektir. Ve diğer platformlarda bu her zaman gereklidir. Ve CPU'nun C ++ sınıflarını anlamadığı fikri gülünç. Bu sadece işaretçi ofsetleri, C yapıları gibi. Bunun için çalışma zamanına ihtiyacınız yok.
MSalters

@MSalters evet, ancak iostreams vb. Gibi standart kitaplık sınıflarının gerçek yöntemleri, derleyici tarafından doğrudan desteklenmek yerine kitaplık işlevleridir. Bununla birlikte, muhtemelen karşılaştırdıkları daha yüksek seviyeli diller C ++ değil, FORTRAN ve PL / I gibi çağdaş dillerdi.
Random832

1
Sanal üye işlevlerine sahip C ++ sınıfları, bir yapıya uzaklıktan çok daha fazlasına çevrilir.
Peter Cordes

4

Bilgisayara bağlıdır. C'nin icat edildiği PDP-11'de longzayıf bir şekilde destekleniyordu (32 bitlik işlemlerin hepsini olmasa da bazılarını destekleyen, satın alabileceğiniz isteğe bağlı bir eklenti modülü vardı). Aynısı, orijinal IBM PC de dahil olmak üzere herhangi bir 16 bit sistemdeki çeşitli dereceler için de geçerlidir. Aynı şekilde 32-bit makinelerde veya 32-bit programlarda 64-bit işlemler için, K&R kitabının zamanında C dili hiçbir 64-bit işlemine sahip değildi. Ve tabii ki 80'ler ve 90'lar boyunca [386 ve bazı 486 işlemciler dahil] birçok sistem ve hatta bugün kayan nokta aritmetiğini ( floatveya double) doğrudan desteklemeyen bazı gömülü sistemler vardı .

Daha egzotik bir örnek için, bazı bilgisayar mimarileri yalnızca "sözcük odaklı" işaretçileri destekler (bellekte iki baytlık veya dört baytlık bir tamsayıya işaret eder) ve bayt işaretçilerinin ( char *veya void *) fazladan bir ofset alanı eklenerek uygulanması gerekir. Bu soru , bu tür sistemler hakkında bazı ayrıntılara giriyor.

O atıfta "çalışma zamanı kitaplığı" işlevleri manuel göreceğiniz olanlar değil, nasıl bir işlev modern derleyici'nın çalışma zamanı kütüphanesinde bu, temel tip işlemleri uygulamak için kullanılır, değil makine tarafından desteklenen . K & R'nin kendilerinin bahsettiği çalışma zamanı kitaplığı The Unix Heritage Society'nin web sitesinde bulunabilir - ldivbölümlerini uygulamak için kullanılan (aynı adı taşıyan C işlevinden farklı) gibi işlevleri görebilirsiniz PDP-11'in eklenti ile bile desteklemediği ve csv(ve cretayrıca csv.c'de) işlevlerden çağrıları ve dönüşleri yönetmek için yığın üzerindeki kayıtları kaydedip geri yükleyen 32 bit değerler .

Ayrıca, büyük olasılıkla, temel makine tarafından doğrudan desteklenmeyen birçok veri türünü desteklememe seçimlerine de atıfta bulunuyorlardı, FORTRAN gibi diğer çağdaş dillerden farklı olarak, CPU'nun temel işaretçi desteğiyle eşleşmeyen dizi anlamsallığına sahipti. C dizileri. C dizilerinin her zaman sıfır dizinli olması ve her kademede her zaman bilinen boyutta olması gerçeği, ancak ilki, dizilerin dizin aralıklarını veya boyutlarını saklamaya gerek olmadığı ve bunlara erişmek için çalışma zamanı kitaplığı işlevlerine gerek olmadığı anlamına gelir - derleyici, gerekli işaretçi aritmetiğini basitçe kodlayabilir.


3

İfade basitçe C'deki veri ve kontrol yapılarının makine odaklı olduğu anlamına gelir.

Burada dikkate alınması gereken iki husus vardır. Birincisi, C dilinin, veri türlerinin nasıl tanımlandığı konusunda enlemlere izin veren bir tanımı (ISO standardı) olmasıdır. Bu, C dili uygulamalarının makineye göre uyarlandığı anlamına gelir . Bir C derleyicisinin veri türleri, derleyicinin hedeflediği makinede mevcut olanla eşleşir, çünkü dilin bunun için enlemi vardır. Bir makinenin 36 bit gibi alışılmadık bir kelime boyutu varsa, o zaman tip intveya longbuna uygun hale getirilebilir. Bunun inttam olarak 32 bit olduğunu varsayan programlar kırılır.

İkinci olarak, bu tür taşınabilirlik sorunları nedeniyle ikinci bir etki vardır. Bir bakıma, K & R'deki ifade bir tür kendi kendini gerçekleştiren kehanet haline geldi veya belki de tam tersi. Yani, yeni işlemcilerin uygulayıcıları, C derleyicilerini destekleme ihtiyacının farkındadır ve "her işlemcinin 80386'ya benzediğini" varsayan çok sayıda C kodu olduğunu bilirler. Mimariler C göz önünde bulundurularak tasarlanmıştır: ve sadece C göz önünde bulundurularak değil, aynı zamanda C taşınabilirliği hakkındaki yaygın yanlış kanılar da göz önünde bulundurularak tasarlanmıştır. Artık 9 bit baytlık veya genel amaçlı kullanım için bir makineyi tanıtamazsınız. Türününchartam olarak 8 bit genişliğindedir. Yalnızca taşınabilirlik uzmanları tarafından yazılan bazı programlar çalışmaya devam edecek: bir araç zinciri, çekirdek, kullanıcı alanı ve kullanışlı uygulamalar içeren eksiksiz bir sistemi makul bir çabayla bir araya getirmek için muhtemelen yeterli olmayacaktır. Başka bir deyişle, C türleri donanımdan alınabilene benziyor çünkü donanım, birçok taşınabilir olmayan C programının yazıldığı bazı diğer donanımlar gibi görünecek şekilde yapıldı.

Bir bilgisayar tarafından doğrudan desteklenmeyen bir veri türü veya kontrol yapısı örneği var mı?

Birçok makine dilinde doğrudan desteklenmeyen veri türleri: çok duyarlıklı tamsayı; bağlantılı liste; karma tablo; karakter dizesi.

Çoğu makine dilinde doğrudan desteklenmeyen kontrol yapıları: birinci sınıf devamlılık; eşyordam / iplik; jeneratör; istisna işleme.

Bunların tümü, çok sayıda genel amaçlı talimat ve daha temel veri türleri kullanılarak oluşturulan önemli çalışma zamanı destek kodunu gerektirir.

C, bazı makineler tarafından desteklenmeyen bazı standart veri türlerine sahiptir. C99'dan beri C karmaşık sayılara sahiptir. İki kayan nokta değerinden oluşurlar ve kütüphane rutinleri ile çalışmak üzere yapılmıştır. Bazı makinelerde kayan nokta birimi yoktur.

Bazı veri türleri ile ilgili olarak, net değildir. Bir makinenin, bir kayıt birimini temel adres olarak ve diğerini ölçeklenmiş yer değiştirme olarak kullanarak adresleme desteği varsa, bu, dizilerin doğrudan desteklenen bir veri türü olduğu anlamına mı gelir?

Ayrıca, kayan noktadan bahsetmişken, standardizasyon var: IEEE 754 kayan nokta. C derleyicinizin neden doubleişlemci tarafından desteklenen kayan nokta biçimiyle aynı fikirde olması, yalnızca ikisinin aynı fikirde olması değil, aynı zamanda bu temsil için bağımsız bir standart olması nedeniyledir.


2

Gibi şeyler

  • Listeler Hemen hemen tüm işlevsel dillerde kullanılır.

  • İstisnalar .

  • İlişkili diziler (Haritalar) - ör. PHP ve Perl'de bulunur.

  • Çöp toplama .

  • Veri türleri / kontrol yapıları birçok dilde bulunur, ancak CPU tarafından doğrudan desteklenmez.


2

Doğrudan desteklenen, işlemcinin komut setine verimli bir şekilde eşleme olarak anlaşılmalıdır.

  • Tam sayı türleri için doğrudan destek, uzun (genişletilmiş aritmetik rutinler gerektirebilir) ve kısa boyutlar (maskeleme gerektirebilir) dışında kuraldır.

  • Kayan nokta türleri için doğrudan destek, bir FPU'nun mevcut olmasını gerektirir.

  • Bit alanları için doğrudan destek olağanüstüdür.

  • Yapılar ve diziler, bir dereceye kadar doğrudan desteklenen adres hesaplaması gerektirir.

  • İşaretçiler her zaman dolaylı adresleme yoluyla doğrudan desteklenir.

  • goto / if / while / for / do, koşulsuz / koşullu dallar tarafından doğrudan desteklenir.

  • bir atlama tablosu uygulandığında anahtar doğrudan desteklenebilir.

  • İşlev çağrıları, yığın özellikleri aracılığıyla doğrudan desteklenir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.