Apa "tipe" data yang dimiliki pointer dalam bahasa C?

30

Saya tahu bahwa pointer menyimpan alamat. Saya tahu bahwa tipe pointer "umumnya" dikenal berdasarkan "tipe" data yang mereka tunjuk. Tapi, pointer masih variabel dan alamat yang mereka pegang harus memiliki "tipe" data. Menurut info saya, alamat berada dalam format heksadesimal. Tapi, saya masih belum tahu apa "tipe" data heksadesimal ini. (Perhatikan bahwa saya tahu apa heksadesimal itu, tetapi ketika Anda mengatakan 10CBA20, misalnya, apakah rangkaian karakter ini? Bilangan bulat? Apa? Ketika saya ingin mengakses alamat dan memanipulasinya .. itu sendiri, saya perlu tahu tipenya. Ini itulah sebabnya saya bertanya.)

Gold_Sky
sumber
17
Pointer bukan variabel , tetapi nilai . Variabel memiliki nilai (dan jika tipenya adalah tipe pointer, nilai itu adalah pointer, dan mungkin alamat zona memori yang berisi sesuatu yang bermakna). Zona memori yang diberikan dapat digunakan untuk menyimpan berbagai nilai dari jenis yang berbeda.
Basile Starynkevitch
29
"alamat berada dalam format heksadesimal" Tidak, itu hanya bit debugger atau format perpustakaan. Dengan argumen yang sama Anda bisa mengatakan mereka berada dalam biner atau oktal.
usr
Anda akan lebih baik bertanya tentang format , bukan tipe . Oleh karena itu beberapa jawaban tidak masuk akal di bawah ini ... (meskipun Kilian tepat).
Lightness Races dengan Monica
1
Saya pikir masalah yang lebih dalam di sini adalah pemahaman tipe OP . Ketika sampai pada itu, nilai-nilai yang Anda manipulasi dalam program Anda hanya sedikit dalam memori. Jenis adalah cara programmer memberi tahu kompiler bagaimana memperlakukan bit-bit itu ketika menghasilkan kode assembly.
Justin Lardinois
Saya kira sudah terlambat untuk mengeditnya dengan semua jawaban itu, tetapi pertanyaan ini akan lebih baik jika Anda membatasi perangkat keras dan / atau sistem operasi, misalnya "pada x64 Linux".
hyde

Jawaban:

64

Jenis variabel pointer adalah .. pointer.

Operasi yang secara formal diperbolehkan untuk Anda lakukan dalam C adalah membandingkannya (dengan pointer lain, atau nilai NULL / nol khusus), untuk menambah atau mengurangi integer, atau melemparkannya ke pointer lain.

Setelah Anda menerima perilaku yang tidak terdefinisi , Anda dapat melihat apa nilainya sebenarnya. Biasanya akan menjadi kata mesin, hal yang sama dengan integer, dan biasanya dapat dilemparkan ke dan dari tipe integer. (Cukup banyak kode Windows yang melakukan ini dengan menyembunyikan pointer di DWORD atau typedef HANDLE).

Ada beberapa arsitektur di mana pointer tidak sederhana karena ingatannya tidak datar. DOS / 8086 'dekat' dan 'jauh'; Ruang memori dan kode PIC berbeda.

pjc50
sumber
2
Anda juga diizinkan untuk mengambil perbedaan antara dua petunjuk p1-p2. Hasilnya adalah nilai integral yang ditandatangani. Secara khusus,&(array[i])-&(array[j]) == i-j
MSalters
13
Sebenarnya, konversi ke tipe integral juga ditentukan, khusus untuk intptr_tdan uintptr_tyang dijamin "cukup besar" untuk nilai pointer.
Matthieu M.
3
Anda dapat bergantung pada konversi agar berfungsi, tetapi pemetaan antara bilangan bulat dan pointer ditentukan oleh implementasi. (Satu-satunya pengecualian adalah 0 -> null, dan bahkan itu hanya ditentukan jika 0 adalah konstan IIRC.)
cHao
7
Penambahan pspecifier ke printf membuat mendapatkan representasi void pointer yang dapat dibaca manusia menjadi didefinisikan, jika implementasi bergantung pada perilaku dalam c.
dmckee
6
Jawaban ini memiliki ide yang umumnya benar, tetapi gagal pada klaim spesifik. Memaksa pointer ke tipe integral bukanlah perilaku yang tidak terdefinisi, dan tipe data Windows HANDLE bukan nilai pointer (mereka bukan pointer yang tersembunyi di tipe data integral, mereka adalah integer yang tersembunyi dalam tipe pointer, untuk mencegah aritmatika).
Ben Voigt
44

Anda terlalu rumit.

Alamat hanyalah bilangan bulat, titik. Idealnya mereka adalah jumlah sel memori yang dirujuk (dalam praktiknya ini menjadi lebih rumit karena segmen, memori virtual dll.).

Sintaks heksadesimal adalah fiksi lengkap yang hanya ada untuk kenyamanan programmer. 0x1A dan 26 adalah jumlah yang persis sama dari jenis yang persis sama , dan tidak juga apa yang digunakan komputer - secara internal, komputer selalu menggunakan 00011010 (serangkaian sinyal biner).

Apakah kompiler memungkinkan Anda memperlakukan pointer karena angka tergantung pada definisi bahasa - bahasa "pemrograman sistem" secara tradisional lebih transparan tentang cara kerja sesuatu di bawah tenda, sementara bahasa "tingkat tinggi" lebih sering mencoba menyembunyikan bare metal dari programmer - tetapi itu tidak mengubah apa pun tentang fakta bahwa pointer adalah angka, dan biasanya tipe angka yang paling umum (angka dengan bit sebanyak arsitektur prosesor Anda).

Kilian Foth
sumber
26
Alamat paling jelas bukan hanya bilangan bulat. Sama seperti angka floating-point yang paling pasti bukan hanya bilangan bulat.
gnasher729
8
Memang. Contoh tandingan yang paling terkenal adalah Intel 8086, di mana pointer adalah dua bilangan bulat.
MSalters
5
@Rob Dalam model memori tersegmentasi, pointer dapat berupa nilai tunggal (alamat relatif terhadap awal segmen; offset) dengan segmen yang tersirat, atau segmen / pemilih dan pasangan offset . (Saya pikir Intel menggunakan istilah "selector"; Saya terlalu malas untuk mencarinya.) Pada 8086, ini direpresentasikan sebagai dua bilangan bulat 16-bit, yang digabungkan untuk membentuk satu alamat fisik 20-bit. (Ya, Anda dapat menangani sel memori yang sama dalam banyak, banyak cara berbeda, jika Anda cenderung: address = (segmen << 4 + offset) & 0xfffff.) Ini dilakukan melalui semua kompatibilitas x86 saat menjalankan dalam mode real.
CVn
4
Sebagai programmer assembler jangka panjang, saya dapat membuktikan bahwa memori komputer tidak lain adalah lokasi memori yang memegang bilangan bulat. Namun, cara Anda memperlakukannya dan melacak apa yang diwakili bilangan bulat itu yang penting. Misalnya Pada sistem saya, angka desimal 4075876853 disimpan sebagai x'F2F0F1F5 ', yang merupakan string' 2015 'dalam EBCDIC. Desimal 2015 akan disimpan sebagai 000007DF sedangkan x'0002015C 'mewakili desimal 2015 dalam format dikemas-desimal. Sebagai programmer assembler, Anda harus melacak ini; kompiler melakukannya untuk bahasa HL.
Steve Ives
7
Alamat dapat dimasukkan ke dalam korespondensi satu-ke-satu dengan bilangan bulat, tetapi semua hal lain di komputer :)
hobbs
16

Pointer hanya itu - pointer. Itu bukan sesuatu yang lain. Jangan mencoba untuk berpikir bahwa itu adalah sesuatu yang lain.

Dalam bahasa seperti C, C ++, dan Objective-C, pointer data memiliki empat jenis nilai yang mungkin:

  1. Pointer dapat menjadi alamat suatu objek.
  2. Pointer dapat menunjuk hanya melewati elemen terakhir dari sebuah array.
  3. Pointer bisa menjadi pointer nol, yang berarti tidak menunjuk ke apa pun.
  4. Pointer dapat memiliki nilai tak tentu, dengan kata lain itu adalah sampah, dan apa pun bisa terjadi (termasuk hal-hal buruk) jika Anda mencoba menggunakannya.

Ada juga pointer fungsi, yang mengidentifikasi fungsi, atau pointer fungsi nol, atau memiliki nilai tak tentu.

Pointer lainnya adalah "pointer to member" di C ++. Ini jelas bukan alamat memori! Sebaliknya, mereka mengidentifikasi anggota dari setiap instance dari kelas. Di Objective-C, Anda memiliki pemilih, yang merupakan sesuatu seperti "penunjuk ke metode instance dengan nama metode dan nama argumen yang diberikan". Seperti pointer anggota, ini mengidentifikasi semua metode dari semua kelas selama mereka terlihat sama.

Anda dapat menyelidiki bagaimana kompiler spesifik mengimplementasikan pointer, tetapi itu adalah pertanyaan yang sama sekali berbeda.

gnasher729
sumber
4
Ada pointer ke fungsi dan, di C ++, pointer ke anggota.
sdenham
C ++ pointer ke anggota bukan alamat memori? Tentu saja. class A { public: int num; int x; }; int A::*pmi = &A::num; A a; int n = a.*pmi;Variabel pmitidak akan banyak digunakan jika tidak berisi alamat memori, yaitu, ketika baris terakhir kode menetapkan, alamat anggota numinstance adari kelas A. Anda bisa melemparkan ini ke intpointer biasa (walaupun kompiler mungkin akan memberi Anda peringatan) dan berhasil melakukannya (membuktikan bahwa itu adalah gula sintaksis untuk pointer lainnya).
dodgethesteamroller
9

Pointer adalah pengalamatan pola bit (mengidentifikasi secara unik untuk tujuan membaca atau menulis) kata penyimpanan dalam RAM. Untuk alasan historis dan konvensional, unit pembaruan adalah delapan bit, yang dikenal dalam bahasa Inggris sebagai "byte" atau dalam bahasa Prancis, agak lebih logis, sebagai oktet. Ini ada di mana-mana tetapi tidak melekat; ukuran lain sudah ada.

Jika saya ingat benar ada satu komputer yang menggunakan kata 29bit; tidak hanya ini bukan kekuatan dua, itu bahkan prima. Saya pikir ini SILLIAC tetapi artikel Wikipedia yang bersangkutan tidak mendukung ini. CAN BUS menggunakan 29 bit alamat tetapi dengan konvensi alamat jaringan tidak disebut sebagai pointer bahkan ketika mereka secara fungsional identik.

Orang-orang terus menyatakan bahwa pointer adalah bilangan bulat. Ini bukan intrinsik atau esensial, tetapi jika kita menafsirkan pola bit sebagai bilangan bulat kualitas berguna ordinalitas muncul, memungkinkan implementasi yang sangat langsung (dan karena itu efisien pada perangkat keras kecil) konstruksi seperti "string" dan "array". Gagasan memori yang berdekatan tergantung pada kedekatan ordinal, dan penentuan posisi relatif dimungkinkan; operasi perbandingan bilangan bulat dan aritmatika dapat diterapkan secara bermakna. Untuk alasan ini hampir selalu ada korelasi kuat antara ukuran kata untuk penyimpanan alamat dan ALU (hal yang melakukan integer matematika).

Terkadang keduanya tidak berkorespondensi. Pada PC awal, bus alamat memiliki lebar 24 bit.

Peter Wone
sumber
Nitpick, hari ini di OS umum, pointer mengidentifikasi lokasi dalam memori virtual, dan tidak ada hubungannya langsung dengan kata RAM fisik (lokasi memori virtual bahkan mungkin tidak ada secara fisik jika berada di halaman memori yang diketahui semua nol oleh OS ).
hyde
@ Hyde - Argumen Anda memiliki manfaat dalam konteks di mana Anda jelas-jelas menginginkannya, tetapi bentuk dominan dari komputer adalah pengontrol tertanam, di mana keajaiban seperti memori virtual adalah inovasi terbaru dengan penyebaran terbatas. Juga, apa yang Anda tunjukkan sama sekali tidak membantu OP untuk memahami petunjuk. Saya pikir beberapa konteks historis akan membuatnya jauh lebih tidak sewenang-wenang.
Peter Wone
Saya tidak tahu apakah berbicara tentang RAM akan membantu OP untuk memahami, karena pertanyaannya adalah secara spesifik tentang apa sebenarnya pointer . Oh, nitpick lain, dalam c pointer dengan titik definisi ke byte (dapat dengan aman dilemparkan ke char*mis. Untuk keperluan penyalinan / pembandingan memori, dan sizeof char==1sebagaimana didefinisikan oleh standar C), bukan kata (kecuali ukuran kata CPU sama dengan ukuran byte).
hyde
Apa pointer secara mendasar adalah kunci hash untuk penyimpanan. Ini adalah variasi bahasa dan platform.
Peter Wone
Pertanyaannya adalah tentang c pointer . Dan pointer jelas bukan kunci hash, karena tidak ada tabel hash, tidak ada algoritma hashing. Mereka secara alami adalah semacam kunci peta / kamus (untuk definisi "peta" yang cukup luas), tetapi bukan kunci hash .
hyde
6

Pada dasarnya setiap komputer modern adalah mesin yang mendorong sedikit. Biasanya itu mendorong bit di dalam kelompok data, yang disebut byte, kata, kata atau qwords.

Satu byte terdiri dari 8 bit, satu kata 2 byte (atau 16 bit), satu kata 2 kata (atau 32 bit) dan satu kata kata 2 kata (atau 64 bit). Ini bukan satu-satunya cara untuk mengatur bit. Manipulasi 128 bit dan 256 bit juga terjadi, seringkali dalam instruksi SIMD.

Instruksi perakitan beroperasi pada register dan alamat memori biasanya beroperasi dalam salah satu formulir di atas.

ALU (unit aritmatika logika) beroperasi pada kumpulan bit seperti jika mereka mewakili bilangan bulat (biasanya format Komplemen Dua), dan FPU seolah-olah mereka di mana nilai-nilai titik mengambang (biasanya gaya IEEE 754 floatdan double). Bagian lain akan bertindak seolah-olah mereka adalah kumpulan data dari beberapa format, karakter, entri tabel, instruksi CPU, atau alamat.

Pada komputer 64 bit yang khas, bundel 8 byte (64 bit) adalah alamat. Kami menampilkan alamat ini secara konvensional dalam format hex (seperti 0xabcd1234cdef5678), tetapi itu hanya cara mudah bagi manusia untuk membaca pola bit. Setiap byte (8 bit) ditulis sebagai dua karakter hex (ekuivalen setiap hex karakter - 0 hingga F - mewakili 4 bit).

Apa yang sebenarnya terjadi (untuk beberapa tingkat sebenarnya) adalah bahwa ada bit, biasanya disimpan dalam register atau disimpan di lokasi yang berdekatan di bank memori, dan kami hanya mencoba menggambarkannya kepada manusia lain.

Mengikuti pointer terdiri dari meminta pengontrol memori untuk memberi kami beberapa data di lokasi itu. Anda biasanya akan meminta pengontrol memori untuk sejumlah byte di lokasi tertentu (well, secara implisit berbagai lokasi, biasanya berdekatan), dan dikirimkan melalui berbagai mekanisme yang tidak akan saya bahas.

Kode biasanya menentukan tujuan untuk data yang akan diambil - register, alamat memori lain, dll - dan biasanya itu adalah ide yang buruk untuk memuat data floating point ke dalam register yang mengharapkan integer, atau sebaliknya.

Jenis data dalam C / C ++ adalah sesuatu yang dicatat oleh kompiler, dan itu mengubah kode apa yang dihasilkan. Biasanya tidak ada yang intrinsik dalam data yang membuatnya benar - benar dari jenis apa pun. Hanya kumpulan bit (disusun dalam bytes) yang dimanipulasi dengan cara seperti integer (atau cara seperti float, atau cara seperti alamat) oleh kode.

Ada pengecualian untuk ini. Ada arsitektur di mana hal-hal tertentu berbeda jenis bit. Contoh paling umum adalah halaman eksekusi yang dilindungi - sementara instruksi memberitahu CPU apa yang dilakukan adalah bit, pada saat run time (memori) halaman yang berisi kode untuk dieksekusi ditandai secara khusus, tidak dapat dimodifikasi, dan Anda tidak dapat mengeksekusi halaman yang tidak ditandai. sebagai halaman eksekusi.

Ada juga hanya baca data (kadang-kadang disimpan dalam ROM yang secara fisik tidak dapat ditulis ke!), Masalah penyelarasan (beberapa prosesor tidak dapat memuat doubledari memori kecuali mereka disejajarkan dengan cara tertentu, atau instruksi SIMD yang memerlukan penyelarasan tertentu), dan berjuta-juta kebiasaan arsitektur lainnya.

Bahkan tingkat detail di atas adalah bohong. Komputer tidak "benar-benar" mendorong bit, mereka benar-benar mendorong voltase dan arus. Tegangan dan arus ini terkadang tidak melakukan apa yang "seharusnya" dilakukan pada tingkat abstraksi bit. Chip dirancang untuk mendeteksi sebagian besar kesalahan seperti itu dan memperbaikinya tanpa abstraksi tingkat yang lebih tinggi harus menyadarinya.

Bahkan itu bohong.

Setiap level abstraksi menyembunyikan yang di bawah ini, dan memungkinkan Anda berpikir tentang menyelesaikan masalah tanpa harus mengingat diagram Feynman untuk dicetak "Hello World".

Jadi pada tingkat kejujuran yang cukup, komputer mendorong bit, dan bit-bit itu diberi makna oleh bagaimana mereka digunakan.

Yakk
sumber
3

Orang-orang telah membuat masalah besar apakah pointer bilangan bulat atau tidak. Sebenarnya ada jawaban untuk pertanyaan-pertanyaan ini. Namun, Anda harus mengambil langkah ke tanah spesifikasi, yang bukan untuk menjadi lemah hati. Kita akan melihat spesifikasi C, ISO / IEC 9899: TC2

6.3.2.3 Petunjuk

  1. Integer dapat dikonversi ke tipe pointer apa saja. Kecuali seperti yang ditentukan sebelumnya, hasilnya adalah implementasi yang ditentukan, mungkin tidak disejajarkan dengan benar, mungkin tidak menunjuk ke entitas dari tipe yang dirujuk, dan mungkin representasi perangkap.

  2. Setiap tipe pointer dapat dikonversi ke tipe integer. Kecuali seperti yang ditentukan sebelumnya, hasilnya ditentukan oleh implementasi. Jika hasilnya tidak dapat direpresentasikan dalam tipe integer, perilaku tidak terdefinisi. Hasilnya tidak harus dalam kisaran nilai dari semua tipe integer.

Sekarang untuk ini, Anda perlu mengetahui beberapa istilah spesifikasi umum. "implementasi terdefinisi" berarti setiap kompiler diperbolehkan untuk mendefinisikannya secara berbeda. Bahkan, kompiler bahkan dapat mendefinisikannya dengan cara yang berbeda tergantung pada pengaturan kompiler Anda. Perilaku tidak terdefinisi berarti kompiler diperbolehkan untuk melakukan apa saja, mulai dari memberikan kesalahan waktu kompilasi hingga perilaku yang tidak dapat dijelaskan, hingga bekerja dengan sempurna.

Dari sini kita dapat melihat bahwa bentuk penyimpanan yang mendasarinya tidak ditentukan, selain itu mungkin ada konversi ke tipe integer. Sejujurnya, setiap kompiler di bawah matahari mewakili pointer di bawah kap sebagai alamat integer (dengan beberapa kasus khusus di mana ia dapat direpresentasikan sebagai 2 integer, bukan hanya 1), tetapi spesifikasi memungkinkan benar-benar apa pun, seperti mewakili alamat sebagai string 10 karakter!

Jika kami maju cepat dari C dan melihat spesifikasi C ++, kami mendapatkan sedikit lebih jelas reinterpret_cast, tetapi ini adalah bahasa yang berbeda, sehingga nilainya untuk Anda dapat bervariasi:

Spesifikasi draft ISO / IEC N337: C ++ 11 (Saya hanya memiliki draft di tangan)

5.2.10 Menafsirkan kembali pemeran

  1. Suatu pointer dapat secara eksplisit dikonversi ke tipe integral apa pun yang cukup besar untuk menahannya. Fungsi pemetaan ditentukan oleh implementasi. [Catatan: Ini dimaksudkan untuk tidak mengejutkan bagi mereka yang mengetahui struktur pengalamatan mesin yang mendasarinya. —Kirim catatan] Nilai tipe std :: nullptr_t dapat dikonversi ke tipe integral; konversi memiliki arti dan validitas yang sama dengan konversi (batal *) 0 ke tipe integral. [Catatan: Reinterpret_cast tidak dapat digunakan untuk mengonversi nilai tipe apa pun menjadi tipe std :: nullptr_t. —Kirim catatan]

  2. Nilai tipe integral atau tipe enumerasi dapat secara eksplisit dikonversi ke pointer. Pointer yang dikonversi menjadi integer dengan ukuran yang cukup (jika ada pada implementasi) dan kembali ke tipe pointer yang sama akan memiliki nilai aslinya; pemetaan antara pointer dan integer jika tidak ditentukan implementasi. [Catatan: Kecuali seperti yang dijelaskan dalam 3.7.4.3, hasil konversi tersebut tidak akan menjadi nilai penunjuk yang diturunkan dengan aman. —Kirim catatan]

Seperti yang dapat Anda lihat di sini, dengan beberapa tahun lagi, C ++ menemukan bahwa aman untuk mengasumsikan bahwa pemetaan ke bilangan bulat ada, sehingga tidak ada lagi pembicaraan tentang perilaku yang tidak terdefinisi (meskipun ada kontradiksi yang menarik antara bagian 4 dan 5 dengan frasa "jika ada pada implementasi")


Sekarang apa yang harus Anda ambil dari ini?

  • Representasi yang tepat dari pointer didefinisikan implementasi. (pada kenyataannya, hanya untuk membuatnya berantakan, beberapa komputer tertanam kecil mewakili pointer nol, (batal ) 0, sebagai alamat 255 untuk mendukung beberapa alamat alias trik yang mereka gunakan) *
  • Jika Anda harus bertanya tentang representasi pointer dalam memori, Anda mungkin tidak pada titik dalam karir pemrograman Anda di mana Anda ingin mengutak-atik mereka.

Taruhan terbaik: casting ke (char *). Spesifikasi C dan C ++ penuh dengan aturan yang menentukan pengemasan array dan struct, dan keduanya selalu memungkinkan casting dari pointer apa saja ke char *. char selalu 1 byte (tidak dijamin dalam C, tetapi oleh C ++ 11 ia telah menjadi bagian dari bahasa yang diamanatkan, sehingga relatif aman untuk menganggapnya 1 byte di mana-mana). Hal ini memungkinkan Anda untuk melakukan aritmatika pointer pada level byte-by-byte tanpa menggunakan benar-benar perlu mengetahui implementasi representasi spesifik dari pointer.

Cort Ammon - Pulihkan Monica
sumber
Bisakah Anda dengan mudah melemparkan fungsi penunjuk ke char *? Saya sedang memikirkan mesin hipotetis dengan ruang alamat terpisah untuk kode dan data.
Philip Kendall
@ PhilipKendall Poin bagus. Saya tidak termasuk bagian dari spec, tetapi fungsi pointer diperlakukan sebagai hal yang sama sekali berbeda dari data pointer dalam spesifikasi karena masalah yang Anda ajukan. Pointer anggota juga diperlakukan berbeda (tetapi mereka juga bertindak sangat berbeda)
Cort Ammon - Reinstate Monica
A charselalu 1 byte dalam C. Mengutip dari standar C: "Ukuran operator menghasilkan ukuran (dalam byte) dari operandnya" dan "Ketika sizeof diterapkan pada operan yang memiliki tipe char, unsigned char, atau char yang ditandatangani, (atau versi yang memenuhi syarat) hasilnya adalah 1. " Mungkin Anda berpikir bahwa byte adalah 8 bit. Itu belum tentu demikian. Agar sesuai dengan standar, byte harus mengandung setidaknya 8 bit.
David Hammen
Spesifikasi ini menjelaskan konversi antara tipe pointer dan integer. Harus selalu diingat bahwa "konversi" antara jenis tidak menyiratkan kesetaraan jenis, atau bahkan representasi biner dari dua jenis dalam memori akan memiliki pola bit yang sama. (ASCII dapat "dikonversi" ke EBCDIC. Big-endian dapat "dikonversi" menjadi little-endian. Dll)
user2338816
1

Pada sebagian besar arsitektur, jenis penunjuk tidak ada lagi setelah diterjemahkan ke dalam kode mesin (kecuali untuk "penunjuk gemuk"). Oleh karena itu, penunjuk ke suatu inttidak dapat dibedakan dari penunjuk ke double, setidaknya dengan sendirinya. *

[*] Meskipun demikian, Anda masih dapat membuat tebakan berdasarkan jenis operasi yang Anda terapkan padanya.

Rufflewind
sumber
1

Suatu hal penting untuk dipahami tentang C dan C ++ adalah tipe apa sebenarnya. Yang benar-benar mereka lakukan adalah menunjukkan kepada kompiler bagaimana menafsirkan sekumpulan bit / byte. Mari kita mulai dengan kode berikut:

int var = -1337;

Bergantung pada arsitektur, integer biasanya diberikan 32 bit ruang untuk menyimpan nilai itu. Itu berarti bahwa ruang dalam memori tempat var disimpan akan terlihat seperti "11111111 11111111 11111010 11000111" atau dalam hex "0xFFFFFAC7". Itu dia. Itu semua yang disimpan di lokasi itu. Semua tipe lakukan adalah memberi tahu kompiler bagaimana menafsirkan informasi itu. Pointer tidak berbeda. Jika saya melakukan sesuatu seperti ini:

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

Kemudian kompiler akan mendapatkan lokasi var, dan kemudian menyimpan alamat itu dengan cara yang sama dengan potongan kode pertama menyimpan nilai -1337. Tidak ada perbedaan dalam cara mereka disimpan, hanya dalam cara mereka digunakan. Bahkan tidak masalah bahwa saya membuat var_ptr pointer ke int. Jika Anda mau, Anda bisa melakukannya.

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

Ini akan menyalin nilai hex var (0xFFFFFAC7) di atas ke lokasi yang menyimpan nilai var2. Jika kita kemudian menggunakan var2, kita akan menemukan bahwa nilainya akan menjadi 4294965959. Bytes dalam var2 sama dengan var, tetapi nilai numeriknya berbeda. Compiler menafsirkannya secara berbeda karena kami memberi tahu bahwa bit-bit itu mewakili panjang yang tidak ditandai. Anda dapat melakukan hal yang sama untuk nilai pointer juga.

unsigned int var3 = (unsigned int)var_ptr;

Anda akhirnya menafsirkan nilai yang mewakili alamat var sebagai int yang tidak ditandatangani dalam contoh ini.

Semoga ini menjelaskan hal-hal untuk Anda dan memberi Anda wawasan yang lebih baik tentang bagaimana C bekerja. Harap dicatat bahwa Anda TIDAK HARUS melakukan hal gila yang saya lakukan dalam dua baris di bawah ini dalam kode produksi aktual. Itu hanya untuk demonstrasi.

BATAL
sumber
1

Bilangan bulat.

Ruang alamat di komputer diberi nomor secara berurutan, mulai dari 0, dan bertambah dengan 1. Jadi, penunjuk akan menyimpan angka integer yang sesuai dengan alamat di ruang alamat.

galois
sumber
1

Jenis-jenis bergabung.

Secara khusus, tipe-tipe tertentu bergabung, hampir seolah-olah mereka diparameterisasi dengan placeholder. Tipe array dan pointer seperti ini; mereka memiliki satu placeholder seperti itu, yang merupakan jenis elemen array atau hal yang ditunjukkan, masing-masing. Jenis fungsi juga seperti ini; mereka dapat memiliki beberapa tempat penampung untuk parameter, dan tempat penampung untuk jenis pengembalian.

Variabel yang dinyatakan memiliki pointer ke char memiliki tipe "pointer to char". Variabel yang dinyatakan memiliki pointer ke pointer ke int memiliki tipe "pointer ke pointer ke int".

A (nilai) ketik "pointer to pointer to int" dapat diubah menjadi "pointer to int" oleh operasi dereference. Jadi, gagasan tipe bukan hanya kata-kata tetapi konstruk yang signifikan secara matematis, menentukan apa yang dapat kita lakukan dengan nilai-nilai tipe (seperti dereferensi, atau lulus sebagai parameter atau menetapkan ke variabel; itu juga menentukan ukuran (jumlah byte) dari operasi pengindeksan, aritmatika, dan kenaikan / penurunan).

NB. Jika Anda ingin mengetahui lebih jauh tentang tipe-tipe, coba blog ini: http://www.goodmath.org/blog/2015/05/13/expressions-and-arity-part-1/

Erik Eidt
sumber