Bir C programı yürütüldüğünde “int” ve “char” gibi veri türü bildiricileri RAM'de depolanıyor mu?


74

Bir C programı çalışırken, veriler öbek ya da yığında depolanır. Değerler RAM adreslerinde saklanır. Peki intya tip göstergeleri (örneğin, ya da char)? Onlar da mı depolanıyor?

Aşağıdaki kodu göz önünde bulundurun:

char a = 'A';
int x = 4;

Burada A ve 4'ün RAM adreslerinde saklandığını okudum. Ama ne hakkında ave x? Kafam karıştı, yürütmenin bunun abir karakter olduğunu ve xbir int olduğunu nereden biliyor ? Yani, bir intve charbir yere RAM belirtilen?

Diyelim ki bir değer RAM'de bir yerde 10011001; Eğer kodu uygulayan program benim ise, bu 10011001'in charbir intmi yoksa bir mi olduğunu nasıl bileyim ?

Anlamadığım şey, bilgisayarın nasıl olduğunu, bir değişkenin değerini 10001 gibi bir adresten okuduğunda, ister bir intister char. Bir programa tıkladığımı hayal edin anyprog.exe. Hemen kod çalıştırılmaya başlar. Bu yürütülebilir dosya saklanan değişkenler Çeşidi olup olmadığı hakkında bilgi içeriyor mu intyoksa char?


24
Bu bilgiler çalışma zamanında tamamen kaybolur. Siz (ve derleyiciniz), belleğin doğru bir şekilde yorumlandığından emin olmak zorundasınız. Peşinde olduğun cevap bu mu?
5gon12eder,

4
Öyle değil. Ne yaptığınızı bildiğinizi varsayar, sağladığınız hafıza adresinde ne bulursa alır ve stdout'a yazar. Yazılan her ne varsa okunabilir bir karaktere karşılık gelirse, sonunda birisinin konsolunda okunabilir bir karakter olarak görünecektir. Eğer buna uymuyorsa, anlamsız veya muhtemelen rastgele okunabilir bir karakter olarak görünecektir.
Robert Harvey,

22
@ user16307 Kısa cevap, statik olarak yazılmış dillerde, bir karakter yazdırırken, derleyicinin bir int yazdırmak için olduğundan farklı bir kod üreteceğidir . Çalışma zamanında artık xbir char olan herhangi bir bilgi yoktur , ancak derleyici seçtiği için çalıştırılan char-print kodudur.
Ixrec

13
@ user16307 Her zaman 65 sayısının ikili gösterimi olarak saklanır. 65 veya A olarak yazdırılıp yazdırılmaması derleyicinizin yazdırmak için ürettiği koda göre değişir . 65’in yanında, aslında bir karakter veya bir int (yani en azından C gibi statik olmayan dillerde değil) yazan bir meta veri yoktur.
Ixrec

2
Tamamen hakkinda burada sormak kavramları anlamak ve bunları kendi başınıza uygulamak, bir derleyici kursu almak isteyebilirsiniz, örneğin Coursera en tek
mucaho

Yanıtlar:


122

Birkaç yorumda gönderdiğiniz soruyu ele almak için (ki gönderinizi düzenlemelisiniz bence):

Anlamadığım, bilgisayarın bir değişkenin değerini okuduğu zaman, bir int veya char ise 10001 gibi bir adres okuduğunu nasıl bildiğidir. Herhangi bir programa, herhangi bir programa tıkladığımı hayal edin. Hemen kod çalıştırılmaya başlar. Bu exe dosyası, değişkenlerin içinde veya char olarak saklanıp saklanmadığı hakkında bilgi içeriyor mu?

O zaman ona bir kod koyalım. Diyelim ki yazıyorsun:

int x = 4;

Ve bunun RAM'de saklandığını varsayalım:

0x00010004: 0x00000004

İlk kısım adres, ikinci kısım değer. Programınız (makine kodu olarak çalışır) çalıştığında, tüm gördüğü 0x00010004değerdir 0x000000004. Bu verilerin türünü 'bilmiyor' ve nasıl kullanılması gerektiğini 'bilmiyor'.

Peki, programınız yapılacak doğru şeyi nasıl belirler? Bu kodu düşünün:

int x = 4;
x = x + 5;

Burada bir okuma ve yazma var. Programınız xbellekten okursa , 0x00000004orada bulur . Ve programın 0x00000005buna eklemeyi biliyor . Programınızın bunun geçerli bir işlem olduğunu bilmesinin nedeni, derleyicinin işlemin tür güvenliği ile geçerli olmasını sağlamasıdır. Sizin derleyici zaten ekleyebilir doğruladı 4ve 5birlikte. Bu nedenle, ikili kodunuz çalıştığında (exe), bu doğrulamayı yapmak zorunda değildir. Sadece her adımı körce uygular, her şeyin yolunda olduğunu varsayarak (aslında sorun olmadığında kötü şeyler olur, tamam değil).

Bunu düşünmenin başka bir yolu da böyle. Sana bu bilgiyi veriyorum:

0x00000004: 0x12345678

Öncekiyle aynı format - soldaki adres, sağdaki değer. Değer ne tür? Bu noktada, kod yürütürken bilgisayarınızın yaptığı değer kadar bilgi biliyorsunuzdur. Bu değere 12743 eklemenizi söyleseydim, bunu yapabilirsiniz. Bu işlemin sonuçlarının tüm sistemde ne olacağı hakkında hiçbir fikriniz yok, ancak iki sayı eklemek gerçekten iyi olduğunuz bir şeydir, böylece başarabilirsiniz . Bu değeri bir intmi yapar ? Mutlaka gerekli değil - Tüm gördüğünüz iki adet 32 ​​bit değer ve toplama işleci.

Belki bazı karışıklıkların ardından verileri geri alıyor. Eğer sahipsek:

char A = 'a';

Bilgisayar akonsolda görüntülenmesini nasıl biliyor ? Bunun için çok fazla adım var. İlki A, bellekteki konumuna gitmek ve onu okumaktır:

0x00000004: 0x00000061

aASCII'deki hex değeri 0x61, bu nedenle yukarıdakiler bellekte göreceğiniz bir şey olabilir. Artık makine kodumuz tamsayı değerini biliyor. Tamsayı değerini görüntülemek için bir karaktere dönüştürmeyi nasıl biliyor? Basitçe söylemek gerekirse, derleyici bu geçişi yapmak için gerekli tüm adımları attığınızdan emin oldu. Ancak bilgisayarınızın kendisi (veya program / exe) bu verilerin türünün ne olduğu hakkında hiçbir fikriniz yok. Bu 32 bitlik değer herhangi bir şey olabilir - int, bir işaretçinin charyarısı double, bir göstergenin, bir dizinin parçası, a'nın bir stringparçası, komutun parçası, vb.


İşte programınızın (exe) bilgisayar / işletim sistemiyle yapabileceği kısa bir etkileşim.

Program: başlamak istiyorum. 20 MB belleğe ihtiyacım var.

İşletim Sistemi: Kullanılmayan 20 MB boş hafıza alanı bulur ve teslim eder

(Önemli not bu geri dönebilirler ki herhangi , hatta bitişik olması gerekmez bellek 20 ücretsiz MB. Bu noktada, program şu anda OS konuşmadan sahip olduğu bellek içinde çalışabilir)

Program: Bellekteki ilk noktanın 32-bit bir tamsayı değişkeni olduğunu kabul edeceğim x.

(Derleyici, diğer değişkenlere erişimin, bellekteki bu noktaya asla dokunmayacağından emin olur. Sistemde, ilk bayt değişken xveya bu değişken xbir tamsayı olduğunu söyleyen hiçbir şey yoktur . Bir benzetme: bir çantanız var. Bu çantaya sadece sarı renkli topları koyacaksınız, birisi daha sonra bir şeyleri çantadan çıkardığında, mavi veya küp bir şey çıkarmaları şok edici olurdu - bir şey korkunç derecede yanlış gitti. Aynı şey bilgisayarlar için de geçerli: program şimdi ilk bellek noktasının x değişkeni olduğunu ve bunun bir tamsayı olduğunu varsayar, bu bellek baytının üzerine başka bir şey yazılmışsa ya da başka bir şey olduğu varsayılırsa - korkunç bir şey oldu. olmadı)

Program: Şimdi 2varsaydığım ilk dört bayta yazacağım x.

Program: 5'e eklemek istiyorum x.

  • X'in değerini geçici bir sicile okur

  • Geçici sicile 5 ekler

  • Geçici yazıcının değerini, hala olduğu varsayılan ilk bayta geri depolar x.

Program: Bir sonraki kullanılabilir baytın char değişkeni olduğunu varsayacağım y.

Program: aDeğişkene yazacağım y.

  • Bir bayt değerini bulmak için bir kütüphane kullanılır. a

  • Bayt, programın varsaydığı adrese yazılır y.

Programın içeriğini görüntülemek istiyorum y

  • İkinci bellek noktasındaki değeri okur

  • Bayttan karaktere dönüştürmek için bir kütüphane kullanır

  • Konsol ekranını değiştirmek için grafik kitaplıklarını kullanır (pikselleri siyahtan beyaza ayarlama, bir satıra kaydırma vb.)

(Ve buradan devam ediyor)

Muhtemelen kapattığınız şey şudur: bellekteki ilk nokta artık olmadığında ne olur x? ya da ikinci artık değil ymi? Birisi xbir charveya ybir işaretçi olarak okuduğunda ne olur ? Kısacası, kötü şeyler olur. Bunların bazıları iyi tanımlanmış davranışlara sahipken, bazıları tanımsız davranışlara sahiptir. Belirsiz davranış tam olarak budur - hiçbir şeyden, hiçbir şeyden, programın veya işletim sisteminin çökmesine kadar bir şey olabilir. İyi tanımlanmış davranışlar bile zararlı olabilir. Degisebilirim ise xtam hacker şey bu - programıma için bir işaretçi ve program bir işaretçi olarak kullanmak için olsun, o zaman benim program çalıştırdığı başlatmak için program alabilirsiniz. Derleyici biz kullanmayan sağlayabileceğiniz orada int xbir şekildestringve o doğadaki şeyler. Makine kodunun kendisi türlerin farkında değildir ve yalnızca talimatların yapmasını istediği şeyi yapar. Çalışma zamanında keşfedilen çok miktarda bilgi var: programın hangi byte belleğini kullanmasına izin verilir? xİlk baytta veya 12'de başlıyor mu ?

Ancak, bunun gibi programları (ve meclis dilinde yapabilirsiniz) yazmanın ne kadar korkunç olacağını hayal edebilirsiniz. Eğer değişkenleri 'bildirerek' başlamak - Kendinizi o bayt 1'dir anlatmak xbayt 2'dir, yve kod, yükleme ve depolama kayıtları her satırı yazarken, (bir insan gibi) hangisinin hatırlamak zorunda xve hangi birincisi y, çünkü sistemin hiçbir fikri yok. Ve siz (bir insan olarak) ne tür xve ne olduğunu hatırlamak zorundasınız y, çünkü yine - sistemin hiçbir fikri yok.


Şaşırtıcı açıklama. Sadece sizin yazdığınız kısım "Tamsayı değerini göstermek için bir karaktere dönüştürmeyi nasıl bilebilir? Basitçe söylemek gerekirse, derleyici bu geçişi yapmak için gerekli tüm adımları attığından emin oldu." benim için hala sisli. İşlemcinin RAM kaydından 0x00000061 aldığını varsayalım. Bu noktadan, ekranda gördüğümüz şeye geçişi yapan başka talimatların (exe dosyasında) olduğunu mu söylüyorsunuz?
user16307

2
@ user16307 evet, ek talimatlar var. Yazdığınız her kod satırı potansiyel olarak birçok talimata dönüştürülebilir. Hangi karakterin kullanılacağına karar vermek için talimatlar var, hangi piksellerin değiştirileceği ve hangi renge dönüştüğü, vs. için talimatlar var. Örneğin, std :: cout kullanmak bir kütüphane kullandığınız anlamına gelir. Konsola yazma kodunuz yalnızca bir satır olabilir, ancak aradığınız işlev (ler) daha fazla satır olacak ve her satır bir çok makine komutuna dönebilir.
Shaz

8
@ user16307 Otherwise how can console or text file outputs a character instead of int Çünkü bir bellek konumunun içeriğini bir tamsayı veya alfasayısal karakterler olarak çıkarmak için farklı bir talimat dizisi vardır. Derleyici değişken türlerini bilir ve uygun derleme zamanında talimat dizisini seçer ve bunu EXE'e kaydeder.
Charles E. Grant,

2
Bayt kodu (veya bayt kodu) olarak genellikle "bayt kodunun kendisi" için farklı bir cümle bulurdum, genellikle çalışma zamanının kaldıracı olması için gerçekten bu verileri depolayabilecek bir ara dili (Java Bytecode veya MSIL gibi) ifade eder. Ayrıca, bu bağlamda "bayt kodunun" neye işaret etmesi gerektiği de tam olarak belli değil. Aksi takdirde, güzel cevap.
jpmc26

6
@ user16307 C ++ ve C # hakkında endişelenmeyin. Bu insanların söylediği şey, bilgisayarların ve derleyicilerin nasıl çalıştığı hakkındaki mevcut anlayışınızın çok üstünde. Anlamaya çalıştığınız şeyin amaçları doğrultusunda, donanım türleri, karakter veya karakter veya herhangi bir şey hakkında hiçbir şey bilmez. Derleyiciye bir değişkenin int olduğu söylendiğinde, bir int olduğu gibi bir hafıza konumunu işlemek için çalıştırılabilir kod üretildi. Hafıza konumunun kendisi türler hakkında bilgi içermez; bu sadece programınızın int olarak ele alınmasına karar vermesidir. Çalışma zamanı türü bilgisi hakkında duyduğunuz her şeyi unutun.
Andres F.

43

Bence asıl sorunuz şu gibi görünüyor: "Eğer derleme zamanında tür silinirse ve çalışma zamanında tutulmazsa, bilgisayar onu bir yorumla kodlayan bir intkod çalıştırıp çalıştırmamayı veya bir olarak yorumlayan bir kodu çalıştırmayı nasıl bilebilir char? "

Ve cevap… bilgisayar değil. Bununla birlikte, derleyici bunu bilir ve doğru kodu ilk önce ikili dosyaya koyar. Değişken şöyle yazılsaydı char, derleyici intprogramdaki gibi davranma kodunu koyamazdı, kod a char.

Orada olan zamanında türünü korumak için nedenler:

  • Dinamik Yazma: Dinamik yazarken, tip kontrolü çalışma zamanında gerçekleşir, bu nedenle açıkça çalışma türünün bilinmesi gerekir. Ancak C dinamik olarak yazılmış değildir, bu yüzden türler güvenle silinebilir. (Bununla birlikte, bunun çok farklı bir senaryo olduğuna dikkat edin. Dinamik Tipler ve Statik Tipler gerçekten aynı şey değildir ve karışık tipte bir dilde, statik türleri silebilir ve yalnızca dinamik türleri tutabilirsiniz.)
  • Dinamik Polimorfizm: Çalışma zamanı türüne göre farklı kodlar uygularsanız, çalışma zamanı türünü etrafında tutmanız gerekir. C, dinamik polimorfizme sahip değildir (bazı özel kodlanmış durumlar dışında, örneğin +operatör dışında hiçbir polimorfizme sahip değildir ), bu nedenle çalışma zamanı türüne ihtiyaç duymaz. Bununla birlikte, yine, çalışma zamanı türü, statik türden zaten farklı bir şeydir; örneğin, Java'da, statik türleri silebilir ve polimorfizm için çalışma zamanı türünü koruyabilirsiniz. Ayrıca, tip-arama kodunu merkezden uzaklaştıracak ve özelleştirecek ve onu nesnenin (veya sınıfın) içine yerleştirecekseniz, çalışma zamanı türüne, örneğin C ++ vtables'a gerek duymayacağınıza da dikkat edin.
  • Çalışma Zamanı Yansıması: Programın çalışma zamanında türlerini yansıtmasına izin verirseniz, çalışma zamanında türleri tutmanız gerekir. Bunu çalışma zamanında birinci dereceden türleri tutan Java ile kolayca görebilirsiniz, ancak derleme zamanında genel türlere yazılan argümanları siler, böylece yalnızca tür yapıcısına ("raw türü") yazabilir, ancak tür argümanına yansıtmazsınız. Yine, C çalışma zamanı yansımasına sahip değildir, bu nedenle türü çalışma zamanında tutmak zorunda değildir.

Türünü çalışma zamanında C'de tutmanın tek nedeni hata ayıklamadır, ancak hata ayıklama genellikle mevcut kaynakla yapılır ve ardından kaynak dosyadaki türü kolayca arayabilirsiniz.

Silme türü oldukça normaldir. Tip güvenliğini etkilemez: tipler derleme zamanında kontrol edilir, derleyici programın tip güvenli olduğu konusunda tatmin edici olduğunda, tiplere artık ihtiyaç duyulmaz (bu nedenle). Statik polimorfizmi etkilemez (aka aşırı yüklenme): aşırı yük çözünürlüğü tamamlandığında ve derleyici doğru aşırı yükü seçtiğinde, artık tiplere ihtiyaç duymaz. Türler ayrıca optimizasyonu da yönlendirebilir, ancak yine de, optimizer türlerine göre optimizasyonlarını seçtikten sonra artık onlara ihtiyaç duymaz.

Çalışma zamanında türleri tutmak, yalnızca çalışma zamanında türlerle bir şeyler yapmak istediğinizde gereklidir.

Haskell, en katı, en titiz, güvenli türden yazılan dillerden biridir ve Haskell derleyicileri genellikle tüm türleri siler. (İstisna türü sınıfları için yöntem sözlüklerinin geçmesi olduğuna inanıyorum.)


3
Hayır! Neden? Bu bilgiye ne için ihtiyaç duyulur? Derleyici char, derlenmiş a'nın okunması için kodu çıkarır. Bir olmayan çıkış kodu mu intbir olmayan çıkış kodu mu, bytebir işaretçi için değil çıkış kodu, sadece verir vermez, sadece bir kodu char. Türüne bağlı olarak hiçbir çalışma zamanı kararı alınmaz. Tipe ihtiyacınız yok. Tamamen ve tamamen anlamsız. İlgili tüm kararlar derleme zamanında zaten yapıldı.
Jörg W Mittag

2
Yok. Derleyici, ikili bir char yazdırmak için kodu koyar. Dönemi. Derleyici bu hafıza adresinde char olduğunu biliyor, bu yüzden ikilide bir char yazdırma kodunu koyar. Çok garip bir nedenle o hafıza adresinde değer olursa değil Bir karakterin olması, o zaman, iyi, kıyametler sonları kaybederler. Temel olarak, bütün bir güvenlik sınıfı bu şekilde işler.
Jörg W Mittag

2
Bir düşünün: Eğer CPU bir şekilde programların veri türlerini bilseydi, o zaman gezegendeki herkes birileri yeni bir tür icat ettiğinde yeni bir CPU almak zorunda kalacaktı. public class JoergsAwesomeNewType {};Görmek? Yeni bir tür icat ettim! Yeni bir CPU almanız gerekiyor!
Jörg W Mittag

9
Hayır. Derleyici, ikili kodda hangi kodu koyacağını bilir. Bu bilgiyi etrafta tutmanın bir anlamı yok. Bir int yazdırıyorsanız, derleyici bir int yazdırma kodunu koyar. Bir karakter yazdırıyorsanız, derleyici bir karakter yazdırma kodunu koyar. Dönemi. Ama bu sadece biraz desen. Bir karakter basmak için kod bit desenini belirli bir şekilde yorumlayacaktır, bir int basmak için kod biti farklı şekilde yorumlayacaktır, fakat bir bit deseninden bir int olan bir bit desenini ayırt etmenin bir yolu yoktur. bir karakter, bu bir dizi bit.
Jörg W Mittag

2
@ user16307: "Exe dosyası hangi veri türünün ne olduğu hakkında bilgi içermiyor mu?" Olabilir. Hata ayıklama verileriyle derlerseniz, hata ayıklama verileri değişken adları, adresleri ve türleri hakkında bilgiler içerir. Ve bazen bu hata ayıklama verisi .exe dosyasında depolanır (bir ikili akış olarak). Ancak çalıştırılabilir kodun bir parçası değildir ve uygulamanın kendisi tarafından yalnızca bir hata ayıklayıcı tarafından kullanılmaz.
Ben Voigt

12

Bilgisayar, hangi adreslerin ne olduğunu “bilmez”, ancak programınızın talimatlarında ne yazıldığının bilgisidir.

Bir char değişkeni yazan ve okuyan bir C programı yazdığınızda, derleyici o veriyi bir yere bir karakter olarak yazan derleme kodu oluşturur ve başka bir yerde bir bellek adresini okuyan ve onu bir karakter olarak yorumlayan başka bir kod vardır. Bu iki işlemi birbirine bağlayan tek şey, bu hafıza adresinin yeridir.

Okuma zamanı geldiğinde, talimatlar "orada hangi veri türünün olduğunu görün" demeyin, sadece "hafızayı kayan nokta olarak yükleyin" gibi bir şey söyler. Okunacak adres değiştiyse veya bir şey bir floattan başka bir şeyle o hafızanın üzerine yazdıysa, CPU bu hafızayı bir float olarak mutlu bir şekilde yükler ve sonuçta her türlü garip şey olabilir.

Kötü benzetme süresi: Deponun hafızada olduğu ve bir şeyler toplayan kişilerin CPU olduğu karmaşık bir nakliye deposunu hayal edin. Depo 'programının' bir kısmı rafa çeşitli eşyalar yerleştirmektedir. Başka bir program gider ve depodaki eşyaları toplar ve kutulara koyar. Çıkarıldıklarında kontrol edilmezler, sadece çöp kutusuna giderler. Tüm depo, senkronize çalışan her şey ile çalışır, doğru öğeler her zaman doğru yerde olur, aksi halde her şey, tıpkı gerçek bir programdaki gibi çöker.


CPU bir kayıt defterinde 0x00000061 bulursa ve onu getirirse nasıl açıklarsınız; ve bunun çıktısını alması gereken konsol programının int değil. Bu exe dosyasında, 0x00000061 adresinin bir karakter olduğunu bilen ve ASCII tablosu kullanarak bir karaktere dönüştüren bazı talimat kodları olduğunu mu kastediyorsunuz?
user16307

7
"Her şey çöküyor" un aslında en iyi senaryo olduğunu unutmayın. "En garip şeyler olur", en iyi ikinci senaryo, "çok tuhaf şeyler olur" daha da kötü, en kötü durum ise "arkanızda kasıtlı bir şekilde onların istedikleri şekilde olmasını istedikleri şeylerdir" aka bir güvenlik açığı.
Jörg W Mittag

@ user16307: Programdaki kod, bilgisayara bu adresi almasını ve ardından kullanılan kodlamaya göre göstermesini söyleyecektir. Bellek konumundaki bu veri ASCII karakterli olsun ya da tamamen çöp olsun, bilgisayar bu konuda endişe duymaz. Bu hafıza adresini, içinde beklenen değerlere sahip olacak şekilde ayarlamaktan başka bir şey sorumluydu. Bazı montaj programlarını denemenizin fayda sağlayabileceğini düşünüyorum.
whatsisname,

1
@ JörgWMittag: gerçekten de. Örnek olarak bir tampon taşmasından bahsetmeyi düşündüm, ancak işleri daha kafa karıştırıcı hale getireceğine karar verdim.
whatsisname,

@ user16307: Verileri ekranda görüntüleyen şey bir programdır. Geleneksel unixen'de bir terminal (DEC VT100 seri terminalini taklit eden bir yazılım parçası - monitörüne klavyesinde yazılanı modeme gönderen ne olursa olsun, monitörüne ve klavyesine sahip bir donanım aygıtı). DOS'ta DOS (aslında VGA kartınızın metin modu ancak bunu görmezden gelmesine izin veriyor) ve Windows'ta command.com. Programınız aslında dizeleri yazdırdığını bilmiyor, sadece bir bayt dizisi yazdırıyor (sayı).
slebetman

8

Öyle değil. C bir kez makine koduna göre derlendiğinde, makine bir demet bit görür. Bu bitlerin nasıl yorumlandığına, bazı ek meta verilere karşılık olarak hangi işlemlerin gerçekleştirildiğine bağlıdır.

Kaynak kodunuza girdiğiniz türler sadece derleyici içindir. Verilerin ne olması gerektiğini söylediğinizi alır ve elinden gelenin en iyisini yapabilmek için, verilerin yalnızca anlamlı şekilde kullanıldığından emin olmaya çalışır. Derleyici, kaynak kodunuzun mantığını kontrol etmek için elinden geldiğince iyi bir iş çıkardıktan sonra, onu makine koduna dönüştürür ve tip verilerini atar, çünkü makine kodunun bunu temsil etme yolu yoktur (en azından çoğu makinede) .


Anlamadığım, bilgisayarın bir değişkenin değerini okuduğu zaman bir int veya char ise 10001 gibi bir adrese ne zaman okuduğunu nasıl bildiğidir. Herhangi bir programa, herhangi bir programa tıkladığımı hayal edin. Hemen kod çalıştırılmaya başlar. Bu exe dosyası, değişkenlerin içinde veya char olarak saklanıp saklanmadığı hakkında bilgi içeriyor mu? -
user16307

@ user16307 Hayır, bir şeyin int veya karakter olup olmadığı hakkında fazla bilgi yoktur. Sonradan başka kimsenin beni dövmeyeceğini farz ederek bazı örnekler ekleyeceğim.
8bittree

1
@ user16307: exe dosyası dolaylı olarak bu bilgiyi içerir. Programı yürüten işlemci, programı yazarken kullanılan türleri önemsemez, ancak çoğu, çeşitli bellek konumlarına erişmek için kullanılan talimatlardan çıkarılabilir.
Bart van Ingen Schenau

@ user16307 aslında biraz fazladan bilgi var. Exe dosyaları bir tamsayının 4 bayt olduğunu bilir, böylece "int a" yazdığınızda, derleyici bir değişken için 4 bayt ayırır ve böylece a ve diğer değişkenlerin adresini hesaplayabilir.
Esben Skov Pedersen,

1
@ arasındaki fark (tip büyüklüğü yanında) pratik bir fark yoktur user16307 int a = 65ve char b = 'A'kod derlenen.

6

Çoğu işlemci, farklı türdeki verilerle çalışmak için farklı talimatlar sağlar; bu nedenle tür bilgileri genellikle oluşturulan makine koduna "girilir". Ek tip meta veri depolamaya gerek yoktur.

Bazı somut örnekler yardımcı olabilir. Aşağıdaki makine kodu, SuSE Linux Enterprise Server (SLES) 10 çalıştıran x86_64 sisteminde gcc 4.1.2 kullanılarak üretildi.

Aşağıdaki kaynak kodunu alın:

int main( void )
{
  int x, y, z;

  x = 1;
  y = 2;

  z = x + y;

  return 0;
}

İşte gcc -Sbana eklenmiş olan yorumlarla , yukarıdaki kaynağa (kullanımda ) karşılık gelen üretilen derleme kodunun eti :

main:
.LFB2:
        pushq   %rbp               ;; save the current frame pointer value
.LCFI0:
        movq    %rsp, %rbp         ;; make the current stack pointer value the new frame pointer value
.LCFI1:                            
        movl    $1, -12(%rbp)      ;; x = 1
        movl    $2, -8(%rbp)       ;; y = 2
        movl    -8(%rbp), %eax     ;; copy the value of y to the eax register
        addl    -12(%rbp), %eax    ;; add the value of x to the eax register
        movl    %eax, -4(%rbp)     ;; copy the value in eax to z
        movl    $0, %eax           ;; eax gets the return value of the function
        leave                      ;; exit and restore the stack
        ret

Takip eden bazı ekstra şeyler var ret, ancak tartışma ile ilgili değil.

%eax32 bitlik genel amaçlı bir veri kaydıdır. yığın işaretçisine%rsp kaydedilmek için ayrılmış 64-bit yazmaç olup, yığına basılan son şeyin adresini içerir. Geçerli yığın çerçevesinin adresini içeren çerçeve işaretçisini%rbp kaydetmek için ayrılan 64 bitlik bir kayıttır . Bir işleve girdiğinizde yığında bir yığın çerçevesi oluşturulur ve işlevin argümanları ve yerel değişkenleri için alan ayırır. Bağımsız değişkenlere ve değişkenlere kare işaretçisinden ofsetler kullanılarak erişilir. Bu durumda, değişken hafızası içinde kayıtlı adresin "altında" 12 bayttır . x%rbp

Yukarıdaki kodda, 32 bit kelimeleri bir konumdan diğerine kopyalamak için kullanılan talimatı kullanarak x(1'de kayıtlı olan -12(%rbp)) tamsayı değerini kayıt defterine kopyalarız. Daha sonra çağırdığımız , tamsayı değerini (at olarak kaydedilmiş ) zaten içinde bulunan değere ekler . Sonra sonucu olduğu gibi kaydederiz . %eaxmovladdly-8(%rbp)%eax-4(%rbp)z

Şimdi bunu değiştirelim, o yüzden doubledeğerler yerine değerlerle uğraşıyoruz int:

int main( void )
{
  double x, y, z;

  x = 1;
  y = 2;

  z = x + y;

  return 0;
}

gcc -STekrar koşmak bize verir:

main:
.LFB2:
        pushq   %rbp                              
.LCFI0:
        movq    %rsp, %rbp
.LCFI1:
        movabsq $4607182418800017408, %rax ;; copy literal 64-bit floating-point representation of 1.00 to rax
        movq    %rax, -24(%rbp)            ;; save rax to x
        movabsq $4611686018427387904, %rax ;; copy literal 64-bit floating-point representation of 2.00 to rax
        movq    %rax, -16(%rbp)            ;; save rax to y
        movsd   -24(%rbp), %xmm0           ;; copy value of x to xmm0 register
        addsd   -16(%rbp), %xmm0           ;; add value of y to xmm0 register
        movsd   %xmm0, -8(%rbp)            ;; save result to z
        movl    $0, %eax                   ;; eax gets return value of function
        leave                              ;; exit and restore the stack
        ret

Birkaç fark. Yerine movlve addl, kullandığımız movsdve addsd(atamak ve çift duyarlıklı yüzen ekleyin). Ara değerleri saklamak yerine %eaxkullanırız %xmm0.

Bu, tipin makine kodunda "pişmiş" olduğunu söylediğimde demek istediğim bu. Derleyici bu özel tip ile başa çıkmak için doğru makine kodunu oluşturur.


4

Tarihsel olarak , C hafızayı bir dizi numaralandırılmış yuva grubundan oluşan bir grup olarak görmüştürunsigned char(ayrıca "bayt" olarak da bilinir, ancak her zaman 8 bit olması gerekmez). Bellekte saklanan herhangi bir şeyi kullanan herhangi bir kodun, bilginin hangi yuvada veya yuvada saklanması gerektiğini ve buradaki bilgilerle ne yapılması gerektiğini bilmesi gerekir [örn. "123: 456 adresinden başlayan dört baytı 32 bit olarak yorumlar. kayan nokta değeri "veya" en son hesaplanan miktarın alt 16 bitini 345: 678 no.lu adreste başlayan iki baytta saklar.] Hafızanın kendisi, hafıza yuvalarında saklanan değerlerin ne anlama geldiğini bilmez ve umursamaz. kod, bir tür kullanarak bellek yazmaya ve başka şekilde okumaya çalıştı, yazma tarafından kaydedilen bit kalıpları, sonuç ne olursa olsun, ikinci türün kurallarına göre yorumlanacaktı.

Örneğin, kod 0x12345678bir 32 bit'e depolanacak unsigned intve ardından unsigned intadresinden ve yukarıdaki değerden art arda iki 16 bitlik değer okumaya çalışacaksa , o zaman hangi yarı değerinin unsigned intnerede saklandığına bağlı olarak , kod değerleri okuyabilir 0x1234 ve 0x5678 veya 0x5678 ve 0x1234.

Bununla birlikte, C99 Standardı, artık belleğin bit kalıplarının neyi temsil ettiği hakkında hiçbir şey bilmeyen bir grup numaralı yuva gibi davranmasını gerektirmez . Bir derleyicinin, bellek yuvaları kendilerine depolanan veri türlerinin farkında olduğu gibi davranmasına izin verilir ve yalnızca unsigned chartürü unsigned charveya yazılanla aynı tür kullanılarak okunmak dışında herhangi bir tür kullanılarak yazılan verilere izin verir. ile; derleyiciler, bellek yuvaları bu kurallara aykırı bir şekilde belleğe erişmeye çalışan herhangi bir programın davranışını keyfi olarak bozma gücüne ve eğilimine sahipmiş gibi davranmalarına izin verilir.

Verilen:

unsigned int a = 0x12345678;
unsigned short p = (unsigned short *)&a;
printf("0x%04X",*p);

bazı uygulamalar 0x1234 yazdırabilir, diğerleri 0x5678 yazdırabilir, ancak C99 Standardına göre bir uygulamanın "FRINK KURALLARI" yazması yasal olacaktır. veya başka herhangi bir şey yapabilir, teoride, aonları yazmak için hangi türden kullanıldıklarını kaydeden donanımları içeren donanımları içermeyi ve bu donanımın, herhangi bir şekilde geçersiz okuma denemelerine cevap vermesini, Samanyoluhaber.com "ÇOK KURALLAR!" çıktı olmak.

Bu tür bir donanımın gerçekten var olup olmadığının önemli olmadığını unutmayın - bu tür bir donanımın yasal olarak var olabileceği gerçeği, derleyicilerin böyle bir sistemde çalışıyor gibi davranan kodlar üretmesini yasal kılar. Derleyici, belirli bir bellek konumunun bir tür olarak yazılacağını ve başka bir şekilde okunacağını belirleyebilirse, donanımı bu tür bir belirleme yapabilen bir sistemde çalışıyor gibi davranabilir ve derleyici yazarının uygun gördüğü kaprisellik derecesine cevap verebilir. .

Bu kuralın amacı, bir tür değeri olan bir bayt grubunun belirli bir zamanda belirli bir değere sahip olduğunu ve o grubun çıkarımı için o zamandan beri aynı türden bir değerin yazılmadığını bilen derleyicilere izin vermekti. bayt sayısı hala bu değeri tutacaktır. Örneğin, bir işlemci bir bayt grubunu bir kayıt defterine okudu ve daha sonra hala kayıt defterindeyken aynı bilgiyi tekrar kullanmak istedi; derleyici, kayıt içeriğini bellekten değeri yeniden okumak zorunda kalmadan kullanabilirdi. Yararlı bir optimizasyon. Kuralın ilk on yılında, kuralın ihlal edilmesi genellikle, bir değişkenin okumak için kullanılandan başka bir tür ile yazılmış olması durumunda, yazının okunan değeri etkileyebileceğini veya etkilemeyeceği anlamına gelir. Bu tür davranışlar bazı durumlarda felaket olabilir, ancak bazı durumlarda zararsız olabilir,

Bununla birlikte, 2009 civarında, CLANG gibi bazı derleyicilerin yazarları, Standardın derleyicilerin istedikleri herhangi bir şeyi yapmasına izin verdiği için, bir tür kullanılarak belleğin yazıldığı ve bir başkası olarak okunduğu durumlarda, derleyicilerin, programların hiçbir zaman alabilecekleri bir girdi alamayacağı sonucuna varması gerektiğini belirlediler böyle bir şeyin gerçekleşmesine neden olur. Standart, derleyicinin, böyle bir geçersiz girdi alındığında, istediği herhangi bir şeyi yapmasına izin verildiğini söylediğinden, yalnızca Standardın hiçbir şart getirmediği durumlarda etkisi olabilecek kod (ve bazı derleyici yazarlarının görüşüne göre) ihmal edilmesi gerektiği alakasız. Bu, takma ad ihlallerinin davranışını, bir okuma isteği verildiğinde, bir okuma isteği ile aynı tür kullanılarak yazılmış son değeri veya başka bir tür kullanılarak yazılmış daha yeni bir değeri keyfi bir şekilde döndürebilen belleğe çevirme davranışını değiştirir,


1
Nasıl RTTI olmadığını anlamayan birine budama yaparken tanımsız davranıştan bahsetmek, karşı sezgisel görünmez
Cole Johnson,

@ColeJohnson: C lehçesi için 2009 öncesi derleyicilerin% 99'unun desteklediği resmi bir isim ya da standart yok, çünkü hem öğretim açısından hem de pratik açıdan farklı diller olarak kabul edilmeleri çok kötü. Aynı isim, 35 yıl boyunca tahmin edilebilir ve optimize edilebilir davranışların bir kısmını ortaya çıkaran lehçeye verildiğinden, söz konusu optimizasyon için söz konusu davranışları ortaya çıkaran lehçe, sözde optimizasyon amacıyla sözde davranışları önlemek için kafa karıştırmaktan kaçınmak zordur. .
supercat,

Tarihsel olarak C, türlerle bu kadar gevşek oynamaya izin vermeyen Lisp makinelerinde çalıştı. 30 yıl önce görülen "tahmin edilebilir ve optimize edilebilir davranışların" pek çoğunun VAX üzerindeki BSD Unix'ten başka hiçbir yerde işe yaramadığından eminim.
prosfilaes

@prosfilaes: Belki de "1999'dan 2009'a kadar kullanılan derleyicilerin% 99'u" daha doğru olabilir mi? Derleyiciler oldukça agresif bir tamsayı optimizasyonları için seçeneklere sahip olsalar bile, onlar sadece - seçeneklerdi. 1999'dan önce hiç bir derleyici görmemiştim, int x,y,z;bu ifadenin verilen ifadenin x*y > z1 veya 0 dışında hiçbir şey yapmamasını ya da takma ad ihlallerinin hiçbir etkisi olmayacağını garanti etmeyen bir modu yoktu. derleyicinin keyfi olarak eski veya yeni bir değer vermesine izin vermekten başka.
supercat,

1
... unsigned charbir tür inşa etmek için kullanılan değerler "nereden geliyor". Bir işaretçiyi bir işaretleyiciye ayrıştırmak unsigned char[], altıgen içeriğini ekranda kısaca göstermek ve ardından işaretçiyi silmek, sonra unsigned char[]ve sonra klavyeden bazı onaltılık sayıları kabul etmek, yeniden işaretçiye kopyalamak ve bu işaretçiyi serbest bırakmak davranış, yazılan sayının görüntülenen sayı ile eşleştiği durumda iyi tanımlanır.
Supercat,

3

C de değil. Diğer diller (örneğin, Lisp, Python) dinamik tiplere sahiptir ancak C statik olarak yazılmıştır. Bu, programınızın hangi tür verileri doğru şekilde yorumlayacağını karakter, tam sayı vb. Olarak bilmesi gerektiği anlamına gelir.

Genellikle derleyici bu konuyu sizin için halleder ve yanlış bir şey yaparsanız, derleme zamanı hatası (veya uyarısı) alırsınız.


Anlamadığım, bilgisayarın bir değişkenin değerini okuduğu zaman bir int veya char ise 10001 gibi bir adrese ne zaman okuduğunu nasıl bildiğidir. Herhangi bir programa, herhangi bir programa tıkladığımı hayal edin. Hemen kod çalıştırılmaya başlar. Bu exe dosyası, değişkenlerin içinde veya char olarak saklanıp saklanmadığı hakkında bilgi içeriyor mu? -
user16307

1
@ user16307 Temelde hayır, tüm bu bilgiler tamamen kaybolur. Bu bilgi olmadan bile işini doğru yapacak kadar iyi tasarlanmış makine koduna kalmış. Bilgisayarın umursadığı tek şey, adres satırında sekiz bit olması 10001. Öyle ya da iş veya derleyici'nın işi, vaka el makinesi veya derleme kod yazarken böyle şeyler yetişmek için, bağlı.
Panzercrisis

1
Dinamik yazmanın, türleri korumanın tek nedeni olmadığını unutmayın. Java statik olarak yazılmıştır, ancak türleri korumalıdır, çünkü türü dinamik olarak yansıtmaya izin verir. Artı, çalışma zamanı polimorfizmine, yani çalışma tipine dayanan ve aynı zamanda tipine ihtiyaç duyduğu yöntem gönderimine sahiptir. C ++, metot gönderim kodunu nesneye (ya da daha çok sınıfa) kendisine koyar, bu nedenle, bir anlamda yazıma ihtiyaç duymaz (elbette, vtable, türün bir parçası olmasına rağmen, gerçekten, en azından türü olan ) korunur, ancak Java, yöntem gönderme kodu merkezileştirilmiştir.
Jörg W Mittag

soruma bak, "bir C programı çalıştırıldığında?" yazdım. talimat kodları arasında dolaylı olarak exe dosyasında saklanmıyorlar ve sonunda hafızada yer alıyorlar mı? Bunu tekrar senin için yazarım: CPU bir kayıtta 0x00000061 bulursa ve onu alırsa; ve bunun çıktısını alması gereken konsol programının int değil. Bu exe dosyasında (makine / ikili kod) 0x00000061 adresini bilen ve ASCII tablosu kullanarak bir karaktere dönüştüren bazı komutların kodu var mı? Eğer öyleyse char int tanımlayıcıları dolaylı olarak ikili dosyada demektir ???
user16307

Değer 0x61 ise ve bir karakter ("a") olarak bildirilirse ve onu görüntülemek için bir rutini çağırırsanız, [sonunda] bu karakteri görüntülemek için bir sistem çağrısı olacaktır. Bir int olarak bildirdiyseniz ve ekran rutini çağırdıysanız, derleyici, 0x61 (ondalık 97) 'yi ASCII dizisine 0x39, 0x37 (' 9 ',' 7 ') dönüştürmek için kod üreteceğini bilecektir. Alt satır: oluşturulan kod farklıdır çünkü derleyici onlara farklı davranmayı bilir.
Mike Harris

3

Sen ayırt etmek zorunda compiletimeve runtimeBir yanda codeve datadiğer taraftan.

Bir makine perspektifinden bakıldığında bunu dediğimiz arasında fark olduğunu codeya instructionsve dediğimiz data. Her şey sayılara iniyor. Fakat bazı diziler - ne diyeceğimiz code- faydalı bulduğumuz bir şey yapar, diğerleri ise sadece crashmakineyi kullanır.

CPU tarafından yapılan iş 4 adımlı basit bir döngüdür:

  • Belirli bir adresten "veri" al
  • Talimatın kodunu çözün (yani, sayıyı "yorumla" instruction)
  • Etkili bir adres oku
  • Sonuçları yürütün ve saklayın

Buna komut döngüsü denir .

Burada A ve 4'ün RAM adreslerinde saklandığını okudum. Peki ya a ve x?

ave xprogram değişkenlerin "içeriğini" bulabildiği adresler için yer tutucular olan değişkenlerdir. Dolayısıyla, değişken ane zaman kullanılırsa kullanılsın içeriğinin adresi etkin bir şekilde bulunura .

Kafa karıştırıcı bir şekilde, yürütme a'nın bir karakter olduğunu ve x'in bir int olduğunu nereden biliyor?

İnfaz hiçbir şey bilmiyor. Giriş bölümünde söylenenden, CPU sadece veri toplar ve bu verileri talimat olarak yorumlar.

Printf taşımasının avantajlı onun çıkan kod nasıl özel bir bellek segmentine başa doğru talimatlar verir yani, içine koyarak girdi ne tür "bilmek" için tasarlanmıştır. Tabii ki, saçma çıktının gnne edilmesi mümkündür: "% s" ile birlikte hiçbir dizginin kaydedilmediği bir adres kullanarak printf()saçma çıktının yalnızca bir 0 ( \0) olduğu rasgele bir bellek konumu tarafından durdurulmasıyla sonuçlanacaktır .

Aynısı bir programın giriş noktası için de geçerlidir. C64'e göre programlarınızı bilinen her adrese (neredeyse) koymak mümkündü. Montaj Programları, sysardından adres verilen bir talimatla başlatıldı : sys 49152montajcı kodunuzu koymak için ortak bir yerdi. Ancak hiçbir şey, örneğin grafik verilerini yüklemenizi engelleyemedi 49152; bu noktadan itibaren "başlattıktan" sonra makine çökmesine neden oldu. Bu durumda, talimat döngüsü “grafiksel verileri” okumak ve onu “kod” olarak yorumlamaya çalışmakla (elbette anlam ifade etmiyordu); etkileri şaşırtıcı şeylerdi;)

Diyelim ki bir değer RAM'de bir yerde 10011001; Eğer kodu uygulayan program benim ise, bu 10011001'in bir karakter mi, yoksa int mi olduğunu nasıl bileyim?

Dediği gibi: "bağlam" - yani önceki ve sonraki talimatlar - verilerin istediğiniz şekilde işlemesine yardımcı olur. Makine açısından bakıldığında, herhangi bir hafıza konumunda bir fark yoktur. intve charsadece anlam ifade eden kelime hazinesidir compiletime; sırasında runtime(montaj düzeyinde), charveya yoktur int.

Anlamadığım, bilgisayarın 10001 gibi bir adresten bir değişkenin değerini okuduğu zaman bir int veya karakter olup olmadığını nasıl bildiğidir.

Bilgisayar hiçbir şey bilmiyor . Programcı yapar. Derlenmiş kod , insanlar için anlamlı sonuçlar üretmek için gerekli olan bağlamı oluşturur.

Bu yürütülebilir dosya, saklanan değişkenlerin int veya char türünde olup olmadığına ilişkin bilgiler içeriyor mu?

Evet ve hayır . Bir a intveya a olup olmadığı bilgisi charkaybolur. Ancak, diğer yandan, bağlam (verilerin depolandığı yerlerin, hafıza konumlarıyla nasıl başa çıkılacağı, verilerin depolandığı) anlatılmaktadır; Öyleyse dolaylı olarak evet, "bilgi" örtük olarak kullanılabilir.


Derleme zamanı ve çalışma zamanı arasında güzel bir ayrım.
Michael Blackburn,

2

Bu tartışmayı sadece C dilinde tutalım .

Bahsettiğiniz program C gibi yüksek bir dilde yazılmıştır. Bilgisayar sadece makine dilini anlamaktadır. Daha yüksek seviyeli diller, programcıya mantığı daha insan dostu bir şekilde ifade etme yeteneği verir; bu da mikroişlemcinin kodunu çözebileceği ve çalıştırabileceği makine koduna çevrilir. Şimdi bahsettiğiniz kodu tartışalım:

char a = 'A';
int x = 4;

Her bir bölümü analiz etmeye çalışalım:

char / int veri türleri olarak bilinir. Bunlar derleyiciye bellek ayırmasını söyler. Bu durumda char1 bayt ve int2 bayt olacaktır. (Lütfen bu bellek boyutunun tekrar mikroişlemciye bağlı olduğunu unutmayın).

a / x , tanımlayıcı olarak bilinir. Şimdi bunlar RAM'deki hafıza yerlerine verilen "kullanıcı dostu" isimleri.

= derleyiciye 'A' ve hafıza konumunda a4 kaydetmesini söyler x.

Bu nedenle int / char veri tipi tanımlayıcıları, program derlemesi sırasında mikroişlemci tarafından değil sadece derleyici tarafından kullanılır. Dolayısıyla bellekte saklanmazlar.


ok int / char veri tipi tanımlayıcıları doğrudan bellekte değişkenler olarak saklanmaz, fakat talimat kodları arasında exe dosyasına dolaylı olarak depolanmaz ve sonunda bellekte yer alırlar mı? Bunu tekrar senin için yazarım: CPU bir kayıtta 0x00000061 bulursa ve onu alırsa; ve bunun çıktısını alması gereken konsol programının int değil. Bu exe dosyasında (makine / ikili kod) 0x00000061 adresini bilen ve ASCII tablosu kullanarak bir karaktere dönüştüren bazı komutların kodu var mı? Eğer öyleyse char int tanımlayıcıları dolaylı olarak ikili dosyada demektir ???
user16307

CPU için hayır, tüm sayıları. Özel örneğiniz için konsolda yazdırma değişkene char veya int olmasına bağlı değildir. Cevabımı, programın yürütülmesine kadar ne kadar yüksek seviyeli bir programın makine diline dönüştürüldüğünün ayrıntı akışıyla güncelleyeceğim.
prasad

2

Buradaki cevabım biraz basitleştirilmiş ve sadece C'ye atıfta bulunacak.

Hayır, tür bilgileri programda saklanmaz.

intveya charCPU için tip göstergeler değildir; sadece derleyiciye.

Derleyici tarafından yaratılan exe int, değişken bir olarak bildirilirse s üzerinde değişiklik yapma talimatına sahip olacaktır int. Aynı şekilde, değişken a olarak bildirilirse char, exe a manipüle etme talimatlarını içerecektir char.

C’de:

int main()
{
    int a = 65;
    char b = 'A';
    if(a == b)
    {
        printf("Well, what do you know. A char can equal an int.\n");
    }
    return 0;
}

Bu program yazdırılacaktır beri, mesajını charve intsahip aynı değerleri RAM içinde.

Eğer merak ediyorsanız Şimdi, printfçıkış yöneten 65bir için intve Abir için charsiz "biçim dizesi" belirtmek zorunda çünkü nasıl olur printfdavranmalı değeri .
(Örneğin, %cbir şekilde değer tedavi etmek anlamına gelir char, ve %d, yine de, her iki durumda da aynı değer bir tamsayı olarak değer tedavi etmek anlamına gelmektedir.)


2
Birinin kullanarak bir örnek kullanmasını umuyordum printf. @OP: int a = 65; printf("%c", a)çıkacaktır 'A'. Neden? Çünkü işlemci umursamıyor. Buna göre, tüm gördüğü bitler. Programınız işlemciye 65 ( 'A'ASCII'deki değeri tesadüfen) olarak kaydetmesini ave ardından memnuniyetle yaptığı bir karakteri çıkarmasını söyledi. Neden? Çünkü umrunda değil.
Cole Johnson,

ama neden bazıları burada C # davasında diyor, hikaye bu değil mi? Bazı yorumları okudum ve C # ve C ++ 'da öykünün (veri türleriyle ilgili bilgi) farklı olduğunu ve CPU bile hesaplama yapmadığını söylüyorlar. Bununla ilgili bir fikrin var mı?
kullanıcı16307

@ user16307 CPU hesaplama yapmıyorsa, program çalışmıyordur. :) C # gelince, bilmiyorum, ama cevabım da orada geçerli sanırım. C ++ gelince, cevabımın orada geçerli olduğunu biliyorum.
BenjiWiebe

0

En düşük seviyede, gerçek fiziksel CPU'da hiçbir tür yoktur (kayan nokta birimlerini yok sayarak). Sadece bit kalıpları. Bir bilgisayar bit kalıplarını değiştirerek çalışır, çok, çok hızlı.

Bu şimdiye kadar yaptığı tüm işlemciler ve yapabildikleri. Bir int veya karakter gibi bir şey yoktur.

x = 4 + 5

Olarak yürütecek:

  1. 00000100'ü sicile yükleyin 1
  2. 00000101 register 2'ye yükleyin
  3. I 2 numaralı kayıt için 1 numaralı kayıt ekleyin ve 1 numaralı kayıtta saklayın

İadd komutu, 1 ve 2 numaralı kayıtları tamsayılar gibi davranan donanımı tetikler. Eğer tamsayıları temsil etmiyorlarsa, daha sonra her şey ters gidebilir. En iyi sonuç genellikle çöküyor.

Kaynakta verilen tiplere göre doğru talimatı seçmek derleyicidedir, ancak CPU tarafından yürütülen gerçek makine kodunda hiçbir yerde tip yoktur.

düzenleme: Gerçek makine kodunun aslında 4 veya 5 veya herhangi bir yerde tamsayıdan bahsetmediğini unutmayın. bu sadece iki bit kalıbı ve iki bit kalıbı alan bir komuttur, onların bit olduğunu varsayar ve bunları bir araya getirir.


0

Kısa cevap, tür derleyicinin ürettiği CPU talimatlarında kodlanmıştır.

Bilginin türü veya büyüklüğü ile ilgili bilgiler doğrudan saklanmamasına rağmen, derleyici bu değişkenlerdeki değerlere erişirken, değiştirirken ve saklarken bu bilgileri takip eder.

İnfazın a'nın char ve x'in int olduğu nasıl bilebilir?

Değil, ama derleyici makine kodunu ürettiğinde bunu bilir. Bir intve bir charfarklı boyutlarda olabilir. Bir karakter bir bayt büyüklüğünde olan ve bir int 4 bayt olan bir mimarisinde, daha sonra değişken xadres 10001 olarak değil, aynı zamanda 10002, 10003 ve kod değerini yüklenmesi gereken 10004. xCPU yazmacına, 4 bayt yükleme talimatını kullanır. Bir char yüklerken, 1 bayt yükleme talimatını kullanır.

İki talimattan hangisini seçmeliyim? Derleyici derleme sırasında karar verir, bellekteki değerleri kontrol ettikten sonra çalışma zamanında yapılmaz.

Kayıtların farklı boyutlarda olabileceğini de unutmayın. Intel x86 CPU'larda EAX 32 bit genişliğinde, yarısı 16 olan AX ve AX her ikisi de 8 bit olan AH ve AL'ya bölünmüş durumda.

Yani bir tamsayı yüklemek istiyorsanız (x86 CPU'larda), tamsayılar için MOV komutunu, bir karakter yüklemek için MOV komutunu kullanın. Her ikisi de MOV olarak adlandırılır, ancak farklı op kodları vardır. Etkili iki farklı talimat olmak. Değişkenin türü kullanılacak talimatta kodlanmıştır.

Aynı şey diğer operasyonlarda da olur. İşlenenlerin boyutuna bağlı olarak ve imzalanmış veya imzasız olsalar bile ekleme yapmak için birçok talimat vardır. Farklı olası ilavelerin listelendiği https://en.wikipedia.org/wiki/ADD_(x86_instruction) adresine bakın .

Diyelim ki bir değer RAM'de bir yerde 10011001; Eğer kodu çalıştıran program benimsem, bu 10011001'in bir karakter mi, yoksa int mi olduğunu nasıl bileyim?

İlk olarak, bir karakter 10011001 olacaktır, ancak bir int 00000000 00000000 00000000 10011001 olacaktır, çünkü bunlar farklı boyutlardadır (yukarıda belirtilen boyutlardaki bir bilgisayarda). Ama signed charvs için durum düşünelim unsigned char.

Bir hafıza konumunda saklanan şey, istediğiniz şekilde yorumlanabilir. C derleyicisinin sorumluluklarının bir kısmı, bir değişkenden saklanan ve okunanların tutarlı bir şekilde yapılmasını sağlamaktır. Bu yüzden, program bir hafıza konumunda neyin saklandığını bilmez, ama önceden her zaman aynı şeyleri okuyup yazacağını kabul etmez. (döküm türleri gibi şeyleri saymamak).


ama neden bazıları burada C # davasında diyor, hikaye bu değil mi? Bazı yorumları okudum ve C # ve C ++ 'da öykünün (veri türleriyle ilgili bilgi) farklı olduğunu ve CPU bile hesaplama yapmadığını söylüyorlar. Bununla ilgili bir fikrin var mı?
kullanıcı16307

0

ama neden bazıları burada C # davasında diyor, hikaye bu değil mi? Bazı yorumları okudum ve C # ve C ++ 'da öykünün (veri türleriyle ilgili bilgi) farklı olduğunu ve CPU bile hesaplama yapmadığını söylüyorlar. Bununla ilgili bir fikrin var mı?

C # gibi tip-kontrol edilen dillerde, tip-kontrol derleyici tarafından yapılır. Benji kodu yazdı:

int main()
{
    int a = 65;
    char b = 'A';
    if(a == b)
    {
        printf("Well, what do you know. A char can equal an int.\n");
    }
    return 0;
}

Sadece derlemeyi reddetti. Benzer şekilde bir dizgiyi ve bir tamsayıyı çarpmaya çalıştıysanız (ekle diyecektim, fakat '+' operatörü dize bitiştirme işlemiyle aşırı yüklenmiş ve sadece işe yarayabilir).

int a = 42;
string b = "Compilers are awesome.";
double[] c = a * b;

Derleyici, dizginizin ne kadar öptüğüne bakılmaksızın, bu C # kodundan makine kodu oluşturmayı reddeder.


-4

Diğer cevaplar, karşılaşacağınız her tüketici cihazının tip bilgilerini saklamadığı için doğrudur. Bununla birlikte, geçmişte (ve günümüzde araştırma bağlamında) etiketli bir mimariyi kullanan birkaç donanım tasarımı olmuştur - hem verileri hem de türü (ve muhtemelen başka bilgileri de) depolarlar. Bunlar en belirgin biçimde Lisp makinelerini içerir .

Benzer bir şeye sahip olan nesne yönelimli programlama için tasarlanmış bir donanım mimarisi hakkında duyduğumu hatırlıyorum ama şimdi bulamıyorum.


3
Soru özellikle o C dilinde (değil Lisp) bahsediyor ve C dili yok devletler değil değişken verileri depolamak. Bir C uygulamasının bunu yapması kesinlikle mümkün olsa da, standart bunu yasaklamadığından, uygulamada asla gerçekleşmez. Soruyla ilgili örnekleriniz varsa, lütfen özel alıntılar sağlayın ve C dili ile ilgili referanslar sağlayın .

Bir Lisp makinesi için bir C derleyicisi yazabilirsiniz, ancak genel olarak bu gün ve yaşta hiç kimse Lisp makinelerini kullanmaz. Bu arada nesne odaklı mimari Rekursiv oldu .
Nathan Ringo,

2
Bence bu cevap yardımcı değil. OP'nin mevcut anlayış seviyesinin ötesinde işleri karmaşık hale getirir. OP'nin bir CPU + RAM'in temel yürütme modelini ve bir derleyicinin sembolik üst seviye kaynağı nasıl çalıştırılabilir bir ikiliye çevirdiğini anlamadığı açıktır. Etiketlenmiş hafıza, RTTI, Lisp, vb., Bencenin bilmesi gerekenlerin ötesinde bir şeydir ve sadece onunla daha fazla karıştırır.
Andres F.

ama neden bazıları burada C # davasında diyor, hikaye bu değil mi? Bazı yorumları okudum ve C # ve C ++ 'da öykünün (veri türleriyle ilgili bilgi) farklı olduğunu ve CPU bile hesaplama yapmadığını söylüyorlar. Bununla ilgili bir fikrin var mı?
kullanıcı16307
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.