Biasanya dalam C, kita harus memberi tahu komputer tipe data dalam deklarasi variabel. Misalnya dalam program berikut, saya ingin mencetak jumlah dua angka floating point X dan Y.
#include<stdio.h>
main()
{
float X=5.2;
float Y=5.1;
float Z;
Z=Y+X;
printf("%f",Z);
}
Saya harus memberi tahu kompiler jenis variabel X.
- Tidak bisakah kompiler menentukan jenisnya
X
sendiri?
Ya, bisa jika saya melakukan ini:
#define X 5.2
Sekarang saya dapat menulis program saya tanpa memberi tahu kompiler jenis X
sebagai:
#include<stdio.h>
#define X 5.2
main()
{
float Y=5.1;
float Z;
Z=Y+X;
printf("%f",Z);
}
Jadi kita melihat bahwa bahasa C memiliki beberapa fitur, yang dapat menentukan jenis data sendiri. Dalam kasus saya ditentukan bahwa itu X
adalah tipe float.
- Mengapa kita harus menyebutkan tipe data, ketika kita mendeklarasikan sesuatu di main ()? Mengapa kompiler tidak dapat menentukan tipe data dari variabelnya sendiri
main()
seperti halnya di#define
.
c
variables
data-types
io
declarations
pengguna106313
sumber
sumber
5.2
adalahdouble
, jadi program pertama membulatkan literal ganda menjadifloat
presisi, kemudian menambahkannya sebagai float, sedangkan putaran kedua representasi ganda 5,1 kembali kedouble
dan menambahkannya kedouble
nilai 5,2 menggunakandouble
tambahan, kemudian putaran hasil perhitungan perhitungan kefloat
presisi . Karena pembulatan terjadi di tempat yang berbeda, hasilnya dapat berubah. Ini hanya satu contoh untuk jenis variabel yang mempengaruhi perilaku program yang identik.#define X 5.2
,X
itu bukan variabel, tetapi sebuah konstanta, jadi ia secara harfiah diganti menjadi preprosesor dengan5.2
tempat yang Anda sebutkanX
. Anda tidak dapat menetapkan kembaliX
.auto
sebenarnya melakukan apa yang Anda inginkan). Di sisi lain, jika Anda pikir Anda tahu apa kode Anda lakukan, dan Anda benar-benar mengetik sesuatu yang lain, mengetik statis seperti ini akan menangkap kesalahan sebelumnya, sebelum menjadi masalah besar. Setiap bahasa menemukan keseimbangan: pengetikan statis, pengetikan tipe, pengetikan dinamis. Untuk beberapa tugas, pengetikan ekstra sebenarnya sepadan. Bagi yang lain, ini sia-sia.Jawaban:
Anda membandingkan deklarasi variabel dengan
#define
s, yang salah. Dengan#define
, Anda membuat pemetaan antara pengidentifikasi dan cuplikan kode sumber. Preprocessor C kemudian akan secara harfiah mengganti setiap kejadian dari pengidentifikasi itu dengan potongan yang disediakan. Penulisanakhirnya menjadi hal yang sama dengan kompiler seperti menulis
Anggap saja sebagai salin & tempel otomatis.
Juga, variabel normal dapat dipindahkan, sementara makro dibuat dengan
#define
tidak bisa (meskipun Anda bisa menggantinya#define
). EkspresiFOO = 7
akan menjadi kesalahan kompiler, karena kami tidak dapat menetapkan "rvalues":40 + 2 = 7
ilegal.Jadi, mengapa kita perlu tipe sama sekali? Beberapa bahasa tampaknya menghilangkan jenis, ini sangat umum dalam bahasa scripting. Namun, mereka biasanya memiliki sesuatu yang disebut "pengetikan dinamis" di mana variabel tidak memiliki tipe tetap, tetapi nilainya. Meskipun ini jauh lebih fleksibel, itu juga kurang berkinerja. C menyukai kinerja, sehingga memiliki konsep variabel yang sangat sederhana dan efisien:
Ada hamparan memori yang disebut "tumpukan". Setiap variabel lokal sesuai dengan area pada stack. Sekarang pertanyaannya adalah berapa lama byte ini harus? Di C, masing-masing jenis memiliki ukuran yang terdefinisi dengan baik yang dapat Anda query
sizeof(type)
. Kompiler perlu mengetahui tipe setiap variabel sehingga dapat memesan jumlah ruang yang benar pada stack.Mengapa konstanta tidak dibuat dengan
#define
memerlukan anotasi jenis? Mereka tidak disimpan di tumpukan. Alih-alih,#define
membuat cuplikan kode sumber yang dapat digunakan kembali dengan cara yang sedikit lebih bisa dipelihara daripada menyalin & menempel. Literal dalam kode sumber seperti"foo"
atau42.87
disimpan oleh kompiler baik sebaris sebagai instruksi khusus, atau dalam bagian data terpisah dari biner yang dihasilkan.Namun, literal memang memiliki tipe. String literal adalah a
char *
.42
adalahint
tetapi dapat juga digunakan untuk tipe yang lebih pendek (penyempitan konversi).42.8
akan menjadidouble
. Jika Anda memiliki literal dan ingin memiliki jenis yang berbeda (misalnya untuk membuat42.8
sebuahfloat
, atau42
sebuahunsigned long int
), maka Anda dapat menggunakan akhiran - surat setelah literal bahwa perubahan bagaimana compiler memperlakukan yang literal. Dalam kasus kami, kami dapat mengatakan42.8f
atau42ul
.Beberapa bahasa memiliki pengetikan statis seperti dalam C, tetapi anotasi jenis bersifat opsional. Contohnya adalah ML, Haskell, Scala, C #, C ++ 11, dan Go. Bagaimana cara kerjanya? Sihir? Tidak, ini disebut "inferensi tipe". Di C # dan Go, kompiler melihat sisi kanan tugas, dan menyimpulkan jenis itu. Ini cukup mudah jika sisi kanan adalah literal seperti
42ul
. Maka jelaslah apa jenis variabel seharusnya. Bahasa lain juga memiliki algoritma yang lebih kompleks yang memperhitungkan bagaimana suatu variabel digunakan. Misalnya, jika Anda melakukannyax/2
, makax
tidak dapat berupa string tetapi harus memiliki beberapa jenis numerik.sumber
#define
kita memiliki konstanta yang secara langsung dikonversi menjadi kode biner - betapapun lama - dan disimpan dalam memori apa adanya.#define X 5.2
?printf
Anda memanggil perilaku yang tidak terdefinisi. Di komputer saya, cuplikan mencetak nilai yang berbeda setiap kali, pada Ideone macet setelah mencetak nol.X*Y
Tidak valid jikaX
danY
adalah pointer, tetapi tidak apa-apa jika ituint
s;*X
tidak valid jikaX
adalahint
, tapi tidak apa-apa jika itu adalah pointer.X dalam contoh kedua tidak pernah mengambang. Itu disebut makro, itu menggantikan nilai makro yang didefinisikan 'X' di sumber dengan nilai. Artikel yang dapat dibaca di #define ada di sini .
Dalam hal kode yang disediakan, sebelum kompilasi preprocessor mengubah kode
untuk
dan itulah yang dikompilasi.
Itu berarti Anda juga dapat mengganti 'nilai' tersebut dengan kode seperti
atau bahkan
sumber
#define FOO(...) { __VA_ARGS__ }
.Jawaban singkatnya adalah tipe kebutuhan C karena sejarah / mewakili perangkat keras.
Sejarah: C dikembangkan pada awal 1970-an dan dimaksudkan sebagai bahasa untuk pemrograman sistem. Kode idealnya cepat dan memanfaatkan kapabilitas perangkat keras sebaik-baiknya.
Jenis inferring pada waktu kompilasi dimungkinkan, tetapi waktu kompilasi yang lambat akan meningkat (lihat kartun 'kompilasi' XKCD. Ini digunakan untuk 'hello world' selama setidaknya 10 tahun setelah C diterbitkan ). Jenis inferring pada saat runtime tidak akan cocok dengan tujuan pemrograman sistem. Runtime inferrence membutuhkan pustaka run time tambahan. C datang jauh sebelum PC pertama. Yang memiliki 256 RAM. Bukan Gigabytes atau Megabytes tetapi Kilobytes.
Dalam contoh Anda, jika Anda menghilangkan jenis
Kemudian kompiler dapat dengan senang hati mengetahui bahwa X & Y adalah float dan membuat Z sama. Bahkan, kompiler modern juga akan berfungsi bahwa X & Y tidak diperlukan dan hanya mengatur Z ke 10.3.
Asumsikan bahwa perhitungan tertanam di dalam suatu fungsi. Penulis fungsi mungkin ingin menggunakan pengetahuan mereka tentang perangkat keras, atau masalah yang sedang dipecahkan.
Apakah dobel lebih cocok daripada pelampung? Membutuhkan lebih banyak memori dan lebih lambat tetapi akurasi hasilnya akan lebih tinggi.
Mungkin nilai kembalinya fungsi bisa int (atau panjang) karena desimal tidak penting, walaupun konversi dari float ke int bukan tanpa biaya.
Nilai kembali juga bisa dibuat ganda menjamin float + float tidak meluap.
Semua pertanyaan ini tampaknya tidak ada gunanya bagi sebagian besar kode yang ditulis hari ini, tetapi sangat penting ketika C diproduksi.
sumber
C tidak memiliki tipe inferensi (itulah yang disebut ketika kompiler menebak tipe variabel untuk Anda) karena sudah lama. Ini dikembangkan pada awal tahun 1970-an
Banyak bahasa yang lebih baru memiliki sistem yang memungkinkan Anda untuk menggunakan variabel tanpa menentukan jenisnya (ruby, javascript, python, dll.)
sumber
true
adalahboolean
), tidak variabel (misalnyavar x
mungkin berisi nilai dari jenis apa pun). Juga, ketik inferensi untuk kasus-kasus sederhana seperti yang dari pertanyaan mungkin telah diketahui satu dekade sebelum C dirilis.implicit none
dalam hal ini Anda harus mendeklarasikan tipe.