Neden C'deki değişkenin veri türünden bahsetmek zorundayız?


19

Genellikle C'de, bilgisayara değişken bildirimindeki veri türünü söylememiz gerekir. Örneğin, aşağıdaki programda, X ve Y olmak üzere iki kayan nokta sayısının toplamını yazdırmak istiyorum.

#include<stdio.h>
main()
{
  float X=5.2;
  float Y=5.1;
  float Z;
  Z=Y+X;
  printf("%f",Z);

}

Derleyiciye X değişkeninin türünü söylemem gerekiyordu.

  • Derleyici türünü belirleyemiyor mu? X tek başına belirleyemiyor mu?

Evet, bunu yapabilirsem yapabilir:

#define X 5.2

Şimdi derleyiciye türünü söylemeden programımı yazabilirim X:

#include<stdio.h>
#define X 5.2
main()
{
  float Y=5.1;
  float Z;
  Z=Y+X;
  printf("%f",Z);

}  

Bu yüzden C dilinin, veri türünü kendi başına belirleyebilen bir tür özelliğe sahip olduğunu görüyoruz. Benim durumumda Xşamandıra tipi olduğunu belirledi .

  • Main () öğesinde bir şey bildirirken neden veri türünden bahsetmek zorundayız? Neden derleyici kendi üzerinde bir değişkenin veri türünü belirleyemiyor main()o olduğu gibi #define.

14
Aslında bu iki program eşdeğer değildir, çünkü biraz farklı çıktılar verebilirler! 5.2a, doubleilk program çift değişmezleri yuvarlar, böylece floathassas ikinci tur, 5.1 arka çift temsil ederken, daha sonra, yüzen olarak ekler doubleve ekler doublekullanılarak değeri 5.2 doubleek, daha sonra bu hesaplama yuvarlar floathassas . Yuvarlama farklı yerlerde gerçekleştiği için sonuç farklı olabilir. Bu, aksi takdirde özdeş bir programın davranışını etkileyen değişken türleri için sadece bir örnektir.

12
Bunu yaptığınızda #define X 5.2, Xbir değişken değil, bir sabittir, yani tam olarak 5.2bahsettiğiniz herhangi bir yerle önişlemci olarak değiştirilir X. Yeniden atayamazsınız X.
scriptin

16
Bir not olarak: bu bir nimet ve lanettir. Bir yandan, derleyici bunu sizin için gerçekten yapabileceği zaman birkaç karakter yazmanız gerekir (C ++ 'ın autogerçekten istediğinizi yapar). Öte yandan, kodunuzun ne yaptığını bildiğinizi düşünüyorsanız ve aslında başka bir şey yazdıysanız, bunun gibi statik yazım, büyük bir sorun haline gelmeden önce bir hata yakalar. Her dil bir dengeye sahiptir: statik yazma, tip çıkarımı, dinamik yazma. Bazı görevler için, fazladan yazma aslında buna değer. Diğerleri için bu bir israftır.
Cort Ammon - Monica'yı yeniden

Ocaml ve / veya Haskell'i öğrenin .... onların türünü çıkarma yeteneklerinden memnun kalacaksınız.
Basile Starynkevitch

Yanıtlar:


46

Değişken bildirimlerini #defines ile karşılaştırıyorsunuz , bu yanlış. A ile #define, bir tanımlayıcı ile kaynak kod snippet'i arasında bir eşleme oluşturursunuz. C önişlemcisi daha sonra bu tanımlayıcının herhangi bir oluşumunu sağlanan snippet ile değiştirecektir. yazı

#define FOO 40 + 2
int foos = FOO + FOO * FOO;

derleyiciye yazı ile aynı şey olur

int foos = 40 + 2 + 40 + 2 * 40 + 2;

Bunu otomatik kopyala ve yapıştır olarak düşünün.

Ayrıca, normal değişkenler yeniden atanabilirken, oluşturulmuş bir makro #defineyapamazsınız (yine de bunu yapabilirsiniz #define). FOO = 7“Değerler” e atamadığımız için ifade bir derleyici hatası olacaktır: 40 + 2 = 7yasadışı.

Peki neden tiplere ihtiyacımız var? Görünüşe göre bazı diller türlerden kurtulur, bu özellikle kodlama dillerinde yaygındır. Ancak, değişkenlerin sabit tiplere sahip olmadığı, ancak değerlerin sahip olduğu “dinamik yazma” adı verilen bir şeyleri vardır. Bu çok daha esnek olsa da, daha az performans gösterir. C performansı sever, bu nedenle çok basit ve verimli bir değişken kavramına sahiptir:

“Yığın” adı verilen bir bellek var. Her yerel değişken, yığındaki bir alana karşılık gelir. Şimdi soru, bu alanın kaç bayt uzunluğunda olması gerektiğidir? C dilinde, her türün iyi tanımlanmış bir boyutu vardır.sizeof(type) . Derleyicinin, yığın üzerinde doğru miktarda yer ayırabilmesi için her değişkenin türünü bilmesi gerekir.

Nedenle oluşturulan sabitlerin #definetür ek açıklamalarına ihtiyacı yoktur? Yığına kaydedilmezler. Bunun yerine, #definekopyala & yapıştır yönteminden biraz daha sürdürülebilir bir şekilde yeniden kullanılabilir kaynak kod parçacıkları oluşturur. Kaynak koddaki "foo"veya gibi değişmez değerler42.87Derleyici özel talimatlar olarak satır içi veya sonuçta ortaya çıkan ikili dosyanın ayrı bir veri bölümünde saklanır.

Ancak değişmez değerler vardır. Dize değişmez değeri a char *. 42Bir olan intfakat aynı zamanda daha kısa türleri (daralma dönüşümü) için de kullanılabilir. 42.8olurdu double. Eğer bir hazır var ve farklı bir tür olmasını istiyorsanız (örneğin yapmak için 42.8bir floatya da 42bir unsigned long int, o zaman son eklerini kullanabilirsiniz) - bir mektup sabitin bundan sonra değişikliklerin nasıl derleyici davranır edebi söyledi. Bizim durumumuzda, biz diyebilirsiniz 42.8fveya42ul .

Bazı diller C'deki gibi statik yazımlara sahiptir, ancak tür açıklamaları isteğe bağlıdır. Örnekler ML, Haskell, Scala, C #, C ++ 11 ve Go'dur. Bu nasıl çalışıyor? Sihirli? Hayır, buna “tür çıkarımı” denir. C # ve Go'da derleyici bir ödevin sağ tarafına bakar ve bunun türünü çıkarır. Sağ taraf gibi bir değişmezse, bu oldukça basittir 42ul. Sonra değişkenin türü ne olmalıdır. Diğer diller de bir değişkenin nasıl kullanıldığını dikkate alan daha karmaşık algoritmalara sahiptir. Örneğin x/2, xbir dize olamaz , ancak sayısal bir tür olmalıdır.


Açıkladığınız için teşekkürler. Anladığım şey, bir değişkenin türünü (yerel veya küresel) beyan ettiğimizde, derleyiciye, yığında bu değişken için ne kadar yer ayırması gerektiğini söylüyoruz. Öte yandan #define, doğrudan ikili koda dönüştürülen bir sabit var - ancak ne kadar uzun olursa olsun - ve olduğu gibi hafızada saklanıyor.
user106313 6:14

2
@ user31782 - tam olarak değil. Bir değişkeni bildirdiğinizde, tür derleyiciye değişkenin hangi özelliklere sahip olduğunu söyler. Bu özelliklerden biri boyuttur; diğer özellikler değerleri nasıl temsil ettiğini ve bu değerler üzerinde hangi işlemlerin gerçekleştirilebileceğini içerir.
Pete Becker

@PeteBecker Peki derleyici bu diğer özellikleri nasıl biliyor #define X 5.2?
user106313

1
Bunun nedeni, printfsize yanlış tür ileterek tanımlanmamış davranışlar başlatmış olmanızdır. Snippet'in her seferinde farklı bir değer yazdırdığı makinemde , Ideone'da sıfırdan sonra çöküyor.
Matteo Italia

4
@ user31782 - "Herhangi bir veri türü üzerinde herhangi bir işlem yapabilir gibi görünüyor" Hayır ve işaretçiler X*Ygeçerli değilse , ancak onlar s tamam ; eğer geçerli olmayan bir olduğunu , ancak bir işaretçi ise sorun yok. XYint*XXint
Pete Becker

4

İkinci örnekte X asla bir şamandıra değildir. Buna makro denir, kaynaktaki tanımlı 'X' makro değerini bu değerle değiştirir. #Define ile ilgili okunabilir bir makale burada .

Sağlanan kod söz konusu olduğunda, derlemeden önce önişlemci kodu değiştirir

Z=Y+X;

için

Z=Y+5.2;

ve bu da derleniyor.

Bu, bu 'değerleri' şu kodla da değiştirebileceğiniz anlamına gelir

#define X sqrt(Y)

ya da

#define X Y

3
Buna sadece makro denir, varyasyonlu bir makro değil. Değişken makro, değişken sayıda argüman alan bir makrodur, örn #define FOO(...) { __VA_ARGS__ }.
DVD

2
Benim kötü, düzeltir :)
James Snell

1

Kısa cevap, geçmiş / donanımı temsil ettiği için C ihtiyaç türleridir.

Tarihçe: C 1970'lerin başında geliştirildi ve sistem programlaması için bir dil olarak tasarlandı. Kod ideal olarak hızlıdır ve donanımın özelliklerinden en iyi şekilde yararlanır.

Derleme zamanında çıkarım türleri mümkün olurdu, ancak zaten yavaş derleme süreleri artacaktır ( XKCD'nin 'derleme' karikatürüne bakın. Bu, C yayınlandıktan sonra en az 10 yıl boyunca 'merhaba dünya' için geçerlidir ). Çalışma zamanında çıkarım türleri, sistem programlamanın amaçlarını yerine getiremezdi. Çalışma zamanı çıkışı, ek çalışma zamanı kitaplığı gerektirir. C ilk bilgisayardan çok önce geldi. 256 RAM vardı. Gigabayt veya Megabayt değil Kilobayt.

Örneğinizde, türleri atlarsanız

   X=5.2;
   Y=5.1;

   Z=Y+X;

Derleyici X & Y'nin yüzer olduğunu ve Z'yi aynı hale getirdiğini mutlu bir şekilde çözebilirdi. Aslında, modern bir derleyici, X & Y'nin gerekli olmadığını ve sadece Z'yi 10.3'e ayarladığını da anlayabilir.

Hesaplamanın bir işlevin içine gömülü olduğunu varsayın. İşlev yazarı, donanım veya çözülen sorunla ilgili bilgilerini kullanmak isteyebilir.

Bir çift bir şamandıradan daha uygun olur mu? Daha fazla bellek alır ve daha yavaştır, ancak sonucun doğruluğu daha yüksek olacaktır.

Belki de fonksiyonun dönüş değeri int (veya uzun) olabilir, çünkü ondalık sayılar önemli değildir, ancak float'tan int'e dönüşüm maliyetsiz değildir.

Dönüş değeri ayrıca, şamandıra + şamandıranın taşmadığından emin olmak için iki kat yapılabilir.

Tüm bu sorular bugün yazılan kodun büyük çoğunluğu için anlamsız görünmektedir, ancak C üretilirken hayati önem taşımaktadır.


1
bu, örneğin, tür bildirimlerinin neden isteğe bağlı yapılmadığını açıklamaz, programcının açık bir şekilde beyan etmesini seçmesine veya sonuçlandırmak için derleyiciye güvenmesine izin verir
gnat

1
Gerçekten de @gnat değildir. Metni değiştirdim ama o zaman bunu yapmanın bir anlamı yoktu. C alanı, aslında 17 in 1 bayt, 2 bayt veya 4 bayt veya bir dize olarak veya bir sözcük içinde 5 bit olarak depolanmasına karar vermek istedi.
itj

0

C, tür çıkarımına sahip değildir (derleyici sizin için bir değişkenin türünü tahmin ettiğinde denir), çünkü eskidir. 1970'lerin başında geliştirildi

Birçok yeni dilde, değişkenleri türlerini belirtmeden (ruby, javascript, python vb.) Belirtmeden kullanmanıza izin veren sistemler bulunur.


12
Bahsettiğiniz dillerin hiçbirinde (Ruby, JS, Python) dil özelliği olarak tür çıkarımı yoktur, ancak uygulamalar verimliliği artırmak için bu dili kullanabilir. Bunun yerine, değerlerin türlere sahip olduğu, ancak değişkenlerin veya diğer ifadelerin bulunmadığı durumlarda dinamik yazmayı kullanırlar .
amon

2
JS vermez izin size ihmal türü - sadece olursa olsun beyan etmek izin vermez oluyor. Değerlerin değişkenleri değil, türlerinin (ör. trueOlduğu boolean) olduğu dinamik yazmayı kullanır (örneğin , var xherhangi bir türün değerini içerebilir). Ayrıca, söz konusu vakalar için, C'nin serbest bırakılmasından on yıl önce muhtemelen bilindiği gibi basit vakalar için tür çıkarımları da bilinmektedir.
scriptin

2
Bu, ifadeyi yanlış yapmaz (bir şeyi zorlamak için ona da izin vermelisiniz). Mevcut tür çıkarımı, C'nin tür sisteminin tarihsel bağlamının bir sonucu olduğu gerçeğini değiştirmez (özel olarak ifade edilen bir felsefi akıl yürütme veya teknik sınırlamanın aksine)
Tristan Burnside

2
C kadar eski olan ML'nin tür çıkarımına sahip olduğu düşünüldüğünde, "eski" iyi bir açıklama değildir. C'nin kullanıldığı ve geliştirildiği bağlam (derleyici için çok az yer kaplayan küçük makineler) daha olası görünmektedir. Neden tür çıkarımlı bazı dil örnekleri (Haskell, ML, heck C # var) yerine dinamik yazım dillerinden bahsettiğinize dair hiçbir fikrim yok .
Voo

2
@BradS. Değişken adının ilk harfi çünkü Fortran iyi bir örnek değil ise kullandığınız sürece, bir tür bildirimi implicit nonebu durumda olmalıdır bir tür beyan ederim.
dmckee
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.