İşaretçilerin C dilinde tuttuğu verilerin türü nedir?


30

İşaretçilerin adresleri olduğunu biliyorum. İşaretçilerin türlerinin, işaret ettikleri veri türüne göre "genellikle" bilindiğini biliyorum. Ancak, işaretçiler hala değişkendir ve sahip oldukları adreslerin "type" verisine sahip olması gerekir. Bilgilerime göre, adresler onaltılık biçimdedir. Ancak, hala "on" veri türünün bu onaltılık olduğunu hala bilmiyorum. (Onaltılık olanın ne olduğunu bildiğime dikkat edin, ancak 10CBA20mesela, örneğin, bu karakter dizgisi nedir? Tamsayılar? Ne? Adrese erişmek ve onu işlemek istediğinizde .. onun türünü bilmem gerekir. bu yüzden soruyorum.


17
İşaretçiler olmayan değişkenler , ancak değerler . Değişkenler değerleri tutar (ve onların türü bir işaretçi türü ise, bu değer bir işaretçidir ve anlamlı bir şey içeren bir bellek bölgesinin adresi olabilir). Belirli bir hafıza bölgesi, farklı tiplerdeki çeşitli değerleri tutmak için kullanılabilir.
Basile Starynkevitch

29
"adresler onaltılık biçimdedir" Hayır, bu yalnızca hata ayıklayıcı veya kitaplık biçimlendirme bitleridir. Aynı argümanla, ikili ya da sekizli olduklarını söyleyebilirsiniz.
usr

Tür hakkında değil, format hakkında soru sormak daha iyi olurdu . Bu nedenle bazı pist dışı cevaplar aşağıda ... (Kilian's yerinde olsa da).
Monica

1
Bence buradaki daha derin mesele OP'nin tip anlayışı . Konuya gelince, programınızdaki manipüle ettiğiniz değerler bellekteki bitlerdir. Tipler, programcının derleyiciye derleme kodu oluştururken bu bitlerin nasıl ele alınacağını söyleme şeklidir.
Justin Lardinois

Sanırım tüm bu cevaplarla düzenlemek için çok geç, fakat donanım ve / veya işletim sistemini, örneğin "x64 Linux'ta" kısıtladıysanız, bu soru daha iyi olurdu.
hyde

Yanıtlar:


64

Bir işaretçi değişkeninin türü .. pointer.

Resmen C'de yapmanıza izin verilen işlemler, onu karşılaştırmak (diğer işaretçilerle veya özel NULL / sıfır değeriyle), tamsayıları eklemek veya çıkarmak ya da diğer işaretçilere atmaktır.

Tanımsız davranışı kabul ettikten sonra , değerin gerçekte ne olduğuna bakabilirsiniz. Genellikle bir makine kelimesi, bir tamsayı ile aynı türde bir şey olacak ve genellikle kayıpsız bir tamsayı tipine veya bu tipten yazılabilir. (Oldukça Windows kodu, bunu DWORD veya HANDLE typedefs içindeki işaretleyicileri gizleyerek yapar).

İşaretçilerin basit olmadığı, belleklerin düz olmadığı bazı mimariler var. DOS / 8086 'yakın' ve 'uzak'; PIC'in farklı hafıza ve kod alanları.


2
Ayrıca, iki işaretçi arasındaki farkı almanıza da izin verilir p1-p2. Sonuç imzalı bir bütündür. Özellikle,&(array[i])-&(array[j]) == i-j
MSalters

13
Aslında, bir integral türüne dönüşüm, özellikle intptr_tve uintptr_tişaretçi değerleri için "yeterince büyük" olduğu garantilidir.
Matthieu M.

3
Çalışılacak dönüştürmeye bağlı olabilirsiniz, ancak tam sayılar ve işaretçiler arasındaki eşleme uygulama tarafından tanımlanır. (Tek istisna, 0 -> null
değerindedir

7
pSpesifikleştiricinin printf'a eklenmesi, c'deki uygulamaya bağlı davranış durumunda tanımlanmış bir boş göstergenin insan tarafından okunabilir bir gösterimini almasını sağlar.
dmckee

6
Bu cevap genel olarak doğru bir fikre sahiptir, ancak belirli taleplerde başarısız olur. İşaretçiyi integral türüne zorlamak tanımsız davranış değildir ve Windows HANDLE veri türleri işaretçi değerleri değildir (integral veri türlerinde gizlenmiş işaretçiler değil, aritmetik önlemek için işaretçi türlerinde gizlenmiş tam sayılardır).
Ben Voigt

44

İşleri çok zorlaştırıyorsun.

Adresler tamsayılar, periyottur İdeal olarak onlar başvurulan bellek hücresinin sayısıdır (pratikte bu bölümler, sanal bellek vb. Nedeniyle daha karmaşık hale gelir).

Onaltılık sözdizimi, yalnızca programcıların rahatlığı için var olan eksiksiz bir kurgudur. 0x1A ve 26, tam olarak aynı türde aynı sayıdadır ve bilgisayarın ne kullandığı da aynı değildir - dahili olarak, bilgisayar her zaman 00011010 (ikili sinyaller dizisi) kullanır.

Olsun ya da olmasın bir derleyici yapmanızı sağlar tedavi "üst düzey" dil daha sık çıplak metal gizlemeye çalışırken "programlama sistemleri" dilleri, geleneksel olarak işler başlık altında nasıl çalıştığı hakkında daha saydamdır - sayılar dil tanımına bağlıdır olarak işaretçiler programlayıcıdan - ancak bu, işaretçilerin sayılar olduğu ve genellikle en yaygın sayı türü olan (işlemci mimariniz kadar çok bit içeren) hiçbir şey değiştirmez.


26
Adresler kesinlikle sadece tamsayılar değil . Kayan nokta sayıları gibi kesinlikle tam sayı değil .
gnasher729

8
Aslında. En iyi bilinen örnek örnek, işaretçilerin iki tam sayı olduğu Intel 8086'dır .
MSalters

5
@Rob Segmentli bir hafıza modelinde, bir işaretçi, tek bir değer (segmentin başlangıcına göre bir adres; bir ofset) olabilir veya bir segment / seçici ve ofset çifti olabilir . (Intel'in "selector" terimini kullandığını düşünüyorum; onu aramak için çok tembelim.) 8086'da bunlar, 20 bitlik bir fiziksel adres oluşturmak için bir araya getirilen iki adet 16 bitlik tamsayı olarak temsil edildi. (Evet, aynı bellek hücresini çok, çok farklı şekillerde adresleyebilirsiniz, eğer çok eğikseniz: address = (segment << 4 + offset) & 0xfffff.) Bu, gerçek modda çalışırken tüm x86 uyumluları boyunca ilerletilir.
CVn

4
Uzun süreli bir montajcı programcısı olarak, bilgisayarın belleğinin tamsayıları tutan bellek konumlarından başka bir şey olmadığını söyleyebilirim. Ancak, onlara nasıl davrandığınızı ve bu tamsayıların neyi temsil ettiğini takip etmeyi önemlidir. Örn. Sistemimde, 4075876853 ondalık sayısı, EBCDIC'deki '2015' dizgisi olan x'F2F0F1F5 'olarak depolanır. Ondalık 2015 000007DF olarak saklanırken, x'0002015C 'paketlenmiş ondalık biçimde 2015'i onlu temsil eder. Bir montajcı programcısı olarak, bunlardan haberdar olmalısınız; derleyici HL dilleri için yapar.
Steve Ives,

7
Adresler tam sayılarla birebir yazışmalara sokulabilir, ancak bilgisayardaki diğer her şey olabilir :)
Ocak

15

Bir işaretçi sadece bu - bir işaretçi. Bu başka bir şey değil. Bunun başka bir şey olduğunu düşünmeye çalışmayın.

C, C ++ ve Objective-C gibi dillerde, veri işaretçilerinin dört olası değeri vardır:

  1. Bir işaretçi, bir nesnenin adresi olabilir.
  2. Bir işaretçi, bir dizinin son elemanını henüz işaret edebilir.
  3. Bir işaretçi boş bir işaretçi olabilir, bu da hiçbir şeye işaret etmediği anlamına gelir.
  4. Bir işaretçi belirsiz bir değere sahip olabilir, başka bir deyişle çöptür ve kullanmaya çalışırsanız her şey olabilir (kötü şeyler dahil).

Bir işlevi tanımlayan veya boş işlev işaretçileri olan veya belirsiz bir değeri olan işlev işaretçileri de vardır.

Diğer işaretçiler, C ++ 'da "üyeye işaretçi" dir. Bunlar kesinlikle hafıza adresleri değil ! Bunun yerine, herhangi bir sınıf örneğinin bir üyesini tanımlarlar . Objective-C'de "belirli bir yöntem adı ve bağımsız değişken isimleri olan bir örnek yönteme işaretçi" gibi seçicilere sahipsiniz. Bir üye işaretçisi gibi, aynı göründüğü sürece tüm sınıfların tüm yöntemlerini tanımlar .

Belirli bir derleyicinin işaretçileri nasıl uyguladığını araştırabilirsiniz, ancak bu tamamen farklı bir sorudur.


4
İşlevlere yönelik işaretçiler ve C ++ 'da üyelere işaretçiler vardır.
sdenham

C ++ işaretçilerine işaretçiler bellek adresi değil mi? Tabii onlar. class A { public: int num; int x; }; int A::*pmi = &A::num; A a; int n = a.*pmi;Değişken pmi, bir bellek adresi içermiyorsa, yani, kodun son satırının belirlediği numgibi a, sınıftaki üyenin üyesinin adresini içermesi halinde, çok kullanmaz A. Bunu sıradan bir intgöstergeye atabilirsiniz (derleyici muhtemelen size bir uyarı verirse de) ve başarıyla kaldırabilir (başka bir işaretçinin sözdizimsel şekeri olduğunu kanıtlayarak).
dodgethesteamroller 10:15

9

Bir işaretçi, RAM'deki bir depolama sözcüğünü adresleyen (okuma veya yazma amacıyla benzersiz şekilde tanımlayan) bir bit desenidir. Tarihsel ve geleneksel nedenlerden dolayı, güncelleme birimi İngilizce olarak "bayt" veya Fransızca olarak, daha mantıklı bir şekilde bir Ekiet olarak bilinen sekiz bittir. Bu her yerde, ancak doğasında değil; başka boyutlar da var.

Doğru hatırlıyorsam, 29bit kelimesini kullanan bir bilgisayar vardı; Bu sadece ikisinin gücü değil, hatta asal. Bunun SILLIAC olduğunu düşündüm, ancak ilgili Wikipedia makalesi bunu desteklemiyor. CAN BUS, 29 bit adresleri kullanır, ancak konvansiyonel olarak ağ adresleri, işlevsel olarak aynı olsalar bile, işaretçiler olarak adlandırılmazlar.

İnsanlar, işaretçilerin tamsayı olduğunu iddia ediyor. Bu ne içsel ne de zaruridir, ancak bit modellerini tamsayı olarak yorumladığımız takdirde , sıralamanın yararlı kalitesi ortaya çıkar, "string" ve "array" gibi yapıların çok doğrudan (ve dolayısıyla küçük donanımlarda etkin) uygulanmasına olanak tanır. Bitişik hafıza kavramı sıralı bitişikliğe bağlıdır ve göreceli konumlandırma mümkündür; tamsayı karşılaştırma ve aritmetik işlemler anlamlı bir şekilde uygulanabilir. Bu nedenle, depolama adreslemesi için kelime büyüklüğü ile ALU (tamsayı matematik yapan şey) arasında neredeyse her zaman güçlü bir korelasyon vardır.

Bazen ikisi uyuşmuyor. Erken bilgisayarlarda adres veriyolu 24 bit genişliğindeydi.


Nitpick, günümüzde ortak işletim sistemlerinde işaretçi, sanal bellekteki konumu tanımlar ve fiziksel bir RAM kelimesiyle doğrudan ilgisi yoktur (sanal bellek konumu, işletim sistemi tarafından sıfır olduğu bilinen bir bellek sayfasındaysa fiziksel olarak bulunmayabilir) ).
hyde

@hyde - Argümanınız açıkça belirlediğiniz bağlamda hak kazanıyor, ancak bilgisayarın baskın biçimi sanal bellek gibi harikaların sınırlı bir şekilde dağıtılan son yenilikler olduğu yerleşik denetleyici. Ayrıca, hiçbir şekilde işaret etmedikleriniz OP'nin işaretçileri anlamalarına yardımcı olur. Bazı tarihsel bağlamların hepsini daha az keyfi hale getireceğini düşündüm.
Peter,

RAM hakkında konuşmanın OP'nin anlaşılmasına yardımcı olup olmadığını bilmiyorum, çünkü soru özellikle işaretçilerin gerçekte ne olduğuyla ilgili. Oh, başka bir nitpick, tanımlayıcıya göre c işaretçisinde byte'a işaret eder ( char*örneğin, bellek kopyalama / karşılaştırma amaçları için ve sizeof char==1C standardı ile tanımlandığı gibi güvenli bir şekilde dökülebilir ), (CPU kelimesi boyutu byte büyüklüğü ile aynı değilse).
hyde

Temel olarak işaretçiler depolama için hash anahtarlarıdır. Bu dil ve platform değişmezdir.
Peter,

Soru c işaretçilerle ilgili . Ve işaretçiler kesinlikle hash anahtarları değildir, çünkü karma tablosu yoktur, karma algoritması yoktur. Doğal olarak bir tür harita / sözlük anahtarıdır ("haritanın" yeterince geniş tanımı için), ancak karma tuşları değildir .
hyde

6

Temel olarak her modern bilgisayar biraz zorlayıcı bir makine. Genellikle, bayt, sözcük, dwords veya qwords adı verilen veri kümelerinde bitleri iter.

Bir bayt 8 bit, 2 bayt (veya 16 bit) kelimesi, 2 dword (veya 32 bit) ve 2 qword (veya 64 bit) kelimesinden oluşur. Bunlar bit düzenlemenin tek yolu değil. 128 bit ve 256 bit manipülasyon da sıklıkla SIMD talimatlarında meydana gelir.

Montaj talimatları kayıtlar üzerinde çalışır ve hafıza adresleri genellikle yukarıdaki formlardan birinde çalışır.

ALU (aritmetik mantık birimleri), tam sayıları (genellikle İki'in Tamamlayıcı formatı) temsil ettikleri gibi bit kümeleri üzerinde, kayan nokta değerlerini (genellikle IEEE 754 tarzı floatve double) olduğu gibi FPU'lar üzerinde çalışırlar . Diğer parçalar, bazı format, karakterler, tablo girişleri, CPU talimatları veya adreslerden oluşan bir veri paketindeymiş gibi davranır.

Tipik bir 64 bit bilgisayarda, 8 baytlık (64 bit) paketler adreslerdir. Bu adresleri geleneksel olarak onaltılı formatta (gibi 0xabcd1234cdef5678) gösteririz, ancak bu sadece insanların bit kalıplarını okuması için kolay bir yoldur. Her bir bayt (8 bit) iki onaltılık karakter olarak yazılmıştır (eşit olarak her onaltılık karakter - 0 - F - 4 bit anlamına gelir).

Gerçekte olan bir şey (aslında bir seviye için), genellikle bir kayıt defterinde saklanan veya bir bellek bankasında bitişik yerlerde saklanan bitlerin olduğu ve onları başka bir insana tarif etmeye çalıştığımızdır.

Bir işaretçiyi takip etmek, bellek denetleyicisinden bize bu konumdaki bazı verileri vermemizi istemekten ibarettir. Genelde, bellek denetleyicisinden belirli bir konumdaki belirli bir bayt sayısını (genellikle dolaylı olarak bir dizi konum, genellikle bitişik) istersiniz ve bu benim girmeyeceğim çeşitli mekanizmalar aracılığıyla iletilir.

Kod genellikle, alınacak veriler için - bir kayıt defteri, başka bir bellek adresi, vb. - bir hedef belirtir ve genellikle, kayan nokta verilerini bir tamsayı bekleyen bir sicile yüklemek veya tam tersi kötü bir fikirdir.

C / C ++ içindeki verinin türü, derleyicinin takip ettiği ve hangi kodun üretildiğini değiştiren bir şeydir. Genellikle, onu aslında herhangi bir türden yapan verilerde özünde hiçbir şey yoktur . Kod tarafından, tamsayı benzeri bir şekilde (ya da kayan noktaya benzeyen bir yol ya da adrese benzeyen bir şekilde) işlenen yalnızca bir bit topluluğu (bayt şeklinde düzenlenmiştir).

Bunun istisnaları var. Bazı şeylerin farklı türde bitler olduğu mimariler var . En yaygın örnek korumalı yürütme sayfalarıdır - CPU'ya ne yapacağını söyleyen talimatlar bit iken, çalışma zamanında yürütmek için kod içeren (bellek) sayfalar özel olarak işaretlenir, değiştirilemez ve işaretlenmemiş sayfaları çalıştıramazsınız yürütme sayfaları olarak.

Ayrıca yalnızca veri (bazen fiziksel olarak yazılamayan ROM'da saklanan!), Hizalama sorunları (bazı işlemciler doublebelirli şekillerde hizalanmadıkça s bellekten yüklenemezler veya belirli hizalama gerektiren SIMD talimatları) ve sayısız diğer mimari tuhaflıklar.

Yukarıdaki detay seviyesi bile bir yalandır. Bilgisayarlar "gerçekten" bitler etrafında itmiyorlar, gerçekten gerilimleri ve akımı itiyorlar. Bu gerilimler ve akımlar bazen bitlerin soyutlama seviyesinde yapmaları gerekeni yapmazlar. Çipler, bu tür hataların çoğunu tespit etmek ve üst düzeyde bir soyutlamadan haberdar olmak zorunda kalmadan bunları düzeltmek için tasarlanmıştır.

Bu bile bir yalan.

Her bir soyutlama seviyesi aşağıdakini gizler ve yazdırmak için Feynman diyagramlarını göz önünde bulundurmadan problemleri çözmeyi düşünmenizi sağlar "Hello World".

Böylece, yeterli bir dürüstlük düzeyinde, bilgisayarlar bitleri zorlar ve bu bitlere nasıl kullanıldığı ile ilgili anlam verilir.


3

İnsanlar, işaretçilerin tamsayı olup olmadığına dair çok şey yaptılar. Aslında bu soruların cevapları var. Bununla birlikte, kalbin zayıflığı için olmayan şartnamelere bir adım atmanız gerekecek. ISO / IEC 9899: TC2 C spesifikasyonuna bir göz atalım.

6.3.2.3 İşaretçiler

  1. Bir tamsayı herhangi bir işaretçi tipine dönüştürülebilir. Önceden belirtilmediği sürece, sonuç uygulama tarafından tanımlanır, doğru şekilde hizalanmayabilir, başvurulan türün bir varlığına işaret etmeyebilir ve bir tuzak temsili olabilir.

  2. Herhangi bir işaretçi tipi, bir tamsayı tipine dönüştürülebilir. Daha önce belirtilmediği sürece, sonuç uygulama tarafından tanımlanır. Sonuç tamsayı türünde gösterilemiyorsa, davranış tanımsızdır. Sonuç, herhangi bir tamsayı türündeki değerler aralığında olması gerekmez.

Şimdi bunun için bazı genel spesifik terimleri bilmeniz gerekecek. "uygulama tanımlı", her bir derleyicinin farklı bir şekilde tanımlamasına izin verilen anlamına gelir. Aslında, bir derleyici sizin derleyici ayarlarınıza bağlı olarak onu farklı şekillerde tanımlayabilir. Tanımlanmamış davranış, derleyicinin bir derleme zamanı hatası vermekten açıklanamayan davranışlara, sadece mükemmel çalışmaya kadar kesinlikle her şeyi yapabileceği anlamına gelir.

Bundan, altta yatan depolama formunun belirtilmediğini görebiliriz, bunun dışında bir tamsayı türüne dönüşüm olabilir . Şimdi doğruyu söylemek gerekirse, güneşin altındaki her derleyici kaputun altındaki işaretçileri tamsayı adresleri olarak temsil eder (sadece 1 yerine 2 tamsayı olarak gösterilebileceği bir çok özel durumla birlikte), 10 karakterli bir dize olarak adres!

Eğer C'yi hızlı bir şekilde ileri alırsak ve C ++ teknik özelliklerine bakarsak, biraz daha netlik kazanırız reinterpret_cast, ancak bu farklı bir dildir, bu yüzden sizin için değeri değişebilir:

ISO / IEC N337: C ++ 11 taslak şartnamesi (sadece taslağım var)

5.2.10 Oyuncuyu yeniden yorumla

  1. Bir işaretçi açıkça tutmak için yeterince büyük olan herhangi bir integral tipine dönüştürülebilir. Haritalama işlevi uygulama tarafından tanımlanmıştır. [Not: Temel makinenin adres yapısını bilenler için şaşırtıcı değildir. —End notu] std :: nullptr_t tipinde bir integral tipine dönüştürülebilir; dönüşüm, integral türüne (void *) 0 dönüşümü ile aynı anlama ve geçerliliğe sahiptir. [Not: Bir reinterpret_cast, herhangi bir türdeki değeri std :: nullptr_t tipine dönüştürmek için kullanılamaz. — Notu yaz]

  2. İntegral tip veya numaralandırma tipinin bir değeri açıkça bir işaretçiye dönüştürülebilir. Yeterli büyüklükte bir tamsayıya dönüştürülen bir işaretçi (eğer uygulamada varsa) ve aynı işaretçi türüne geri dönmek orijinal değerine sahip olacaktır; İşaretçiler ve tamsayılar arasındaki eşlemeler aksi takdirde uygulama tarafından tanımlanır. [Not: 3.7.4.3'te açıklananlar dışında, böyle bir dönüştürmenin sonucu güvenli bir şekilde türetilmiş bir işaretçi değeri olmayacaktır. — Notu yaz]

Burada görebileceğiniz gibi, birkaç yıl daha kuşağı altında olan C ++, tamsayılara yönelik bir eşlemenin var olduğunu varsaymanın güvenli olduğunu buldu, bu yüzden artık tanımsız davranıştan söz edilmiyor (4. ve 4. bölümler arasında ilginç bir çelişki olmasına rağmen). 5 "Uygulamada böyle bir şey varsa" cümlesiyle


Şimdi bundan ne çıkarmalısınız?

  • İşaretçilerin tam gösterimi uygulama tanımlanır. (aslında, sadece daha karmaşık hale getirmek için, bazı küçük gömülü bilgisayarlar, kullandıkları bazı adres örtüşme numaralarını desteklemek için 255 adresi olarak , boş göstericiyi (void ) 0 temsil eder ) *
  • İşaretçilerin bellekteki temsili hakkında sorular sormanız gerekiyorsa, muhtemelen programlama kariyerinizde bunlarla uğraşmak istediğiniz bir noktada değilsinizdir.

En iyi bahis: a (char *) yapmak. C ve C ++ özellikleri, dizilerin ve yapıların paketlenmesini belirleyen kurallarla doludur ve her ikisi de, herhangi bir işaretçinin bir karaktere basılmasına her zaman izin verir *. char her zaman 1 bayttır (C'de garanti edilmez, ancak C ++ 11 tarafından dilin zorunlu bir parçası haline gelmiştir, bu nedenle her yerde 1 bayt olduğunu varsaymak nispeten güvenlidir). Bu, işaretçilerin uygulamaya özel sunumlarını bilmeye ihtiyaç duymadan, bayt bayt düzeyinde bazı işaretçi aritmetik işlemlerini yapmanızı sağlar.


Bir işlev göstergesini mutlaka bir simgesine çevirebilir misiniz char *? Kod ve veriler için ayrı adres alanları olan varsayımsal bir makine düşünüyorum.
Philip Kendall

@PhilipKendall İyi nokta. Spesifikasyonun bir bölümünü dahil etmedim, ancak işlev işaretçileri, tam olarak ortaya attığınız sorun nedeniyle, spesifikasyondaki veri işaretçilerinden tamamen farklı bir şey olarak değerlendirilir. Üye işaretçilere farklı muamele de yapılır (ancak aynı zamanda çok farklı davranırlar)
Cort Ammon - Reinstate Monica

A char, C'de her zaman 1 bayttır. (veya nitelikli bir versiyonu) sonuç 1'dir. " Belki bir bayt 8 bit uzunluğunda olduğunu düşünüyorsunuz. Bu mutlaka böyle değil. Standartla uyumlu olması için bir bayt en az 8 bit içermelidir.
David Hammen

Spec, işaretçi ve tamsayı türleri arasında dönüşüm yapmayı açıklar . Türler arasındaki bir "dönüşümün" türlerin eşitliği anlamına gelmediği, hatta bellekteki iki türün ikili gösteriminin aynı bit desenine sahip olamayacağı daima akılda tutulmalıdır. (ASCII
EBCDIC'e

1

Çoğu mimaride, işaretçinin türü makine koduna çevrildikten sonra (belki de "yağ işaretçileri" hariç) sona erer. Bu nedenle, bir işaretçi için bir intişaretçi double, en azından kendi başına bir işaretçi için bir ayırt edilemez .

[*] Bununla birlikte, uyguladığınız işlem türlerine dayanarak tahminlerde bulunabilirsiniz.


1

C ve C ++ hakkında anlaşılması gereken önemli bir şey aslında ne tür olduğu. Tek yaptıkları derleyiciye bir bit / bayt kümesinin nasıl yorumlanacağını göstermektir. Aşağıdaki kodla başlayalım:

int var = -1337;

Mimariye bağlı olarak, bir tamsayıya genellikle bu değeri depolamak için 32 bit alan verilir. Bu, var depolandığı alandaki boşluğun "11111111 11111111 11111010 11000111" veya altıgen "0xFFFFFAC7" gibi görüneceği anlamına gelir. Bu kadar. Bu yerde depolanan tek şey budur. Bütün türler derleyiciye bu bilgiyi nasıl yorumlayacağını söyler. İşaretçiler farklı değil. Böyle bir şey yaparsam:

int* var_ptr = &var;   //the ampersand is telling C "get the address where var's value is located"

Sonra derleyici var konumunu alacaktır ve daha sonra bu adresi ilk kod parçacığı -1337 değerini kaydedeceği şekilde saklar. Nasıl depolandıkları, sadece nasıl kullanıldığı konusunda hiçbir fark yoktur. Var_ptr'yi bir int için gösterici yapmamın önemi yok. Eğer istersen, yapabilirsin.

unsigned int var2 = *(unsigned int*)var_ptr;

Bu yukarıdaki var değerinin (0xFFFFFAC7) onaltılık değerini var2'nin değerini depolayan yere kopyalayacaktır. Var2 kullanacak olsaydık, değerin 4294965959 olacağını bulurduk. Var2'deki baytlar var ile aynıdır, ancak sayısal değer farklıdır. Derleyici bunları farklı şekilde yorumladı çünkü bu bitlerin işaretsiz bir süreyi temsil ettiğini söyledik. İşaretçi değeri için de aynı şeyi yapabilirsiniz.

unsigned int var3 = (unsigned int)var_ptr;

Bu örnekte, var adresini gösteren değeri imzasız bir int olarak yorumlayacaksınız.

Umarım bu sizin için işleri açıklığa kavuşturur ve size C'nin nasıl çalıştığı hakkında daha iyi bir fikir verir. Lütfen asıl üretim kodunda aşağıdaki iki satırda yaptığım çılgınca şeylerden hiçbirini YAPMAMALIDIR . Bu sadece gösteri içindi.


1

Tamsayı.

Bir bilgisayardaki adres alanı, 0'dan başlayarak sırayla numaralandırılır ve 1 ile artar. Böylece bir işaretçi, adres alanındaki bir adrese karşılık gelen bir tamsayıya sahip olur.


1

Türleri birleştirir.

Özellikle, bazı tipler neredeyse neredeyse yer tutucularla parametrelenmiş gibi birleştirilir. Dizi ve işaretçi türleri şöyle; Sırasıyla dizideki öğenin türü ya da işaret ettiği şeyin gibi bir yer tutucusuna sahiptirler. Fonksiyon tipleri de aynı şekilde; parametreler için birden fazla yer tutucusuna ve geri dönüş türü için bir yer tutucusuna sahip olabilirler.

Bir işaretçiyi char'a tutacağı bildirilen değişken, "pointer to char" türündedir. Bir işaretçiyi int işaretçisine tutacağı bildirilen değişken, "pointer to pointer to int" türüne sahiptir.

Bir "değeri" için pointer için int "A değeri (") int "pointer için" bir değişiklik işlemi tarafından değiştirilebilir. Bu nedenle, tür kavramı sadece sözcükler değil, matematiksel olarak anlamlı bir yapıdır, türün değerleriyle yapabileceklerimizi dikte eder (değişkenlik veya parametre olarak geçme veya değişkene atama; ayrıca boyutunu (bayt sayısı) belirler. indeksleme, aritmetik ve artırma / azaltma işlemleri).

PS Türlere derinlemesine ulaşmak istiyorsanız bu blogu deneyin: http://www.goodmath.org/blog/2015/05/13/expressions-and-arity-part-1/

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.