C'de neden bazı insanlar imleci serbest bırakmadan önce kullanıyor?


167

Ben eski bir kod tabanı üzerinde çalışıyorum ve hemen hemen ücretsiz () her çağrışımı kendi argümanı bir döküm kullanır. Örneğin,

free((float *)velocity);
free((float *)acceleration);
free((char *)label);

burada her işaretçi karşılık gelen (ve eşleşen) tiptedir. Bunu yapmanın bir anlamı yok. Çok eski bir kod, bu yüzden bir K&R şey olup olmadığını merak bıraktım. Eğer öyleyse, bunu gerektirebilecek eski derleyicileri desteklemek istiyorum, bu yüzden onları kaldırmak istemiyorum.

Bu kalıpları kullanmanın teknik bir nedeni var mı? Onları kullanmak için pragmatik bir neden bile görmüyorum. Veri tipini boşaltmadan hemen önce kendimize hatırlatmanın anlamı nedir?

EDIT: Bu soru diğer sorunun bir kopyası değil . Diğer soru, yakın seçmenlerin tüm cevapları okuyup okumadıklarının açık olduğunu düşündüğüm bu sorunun özel bir örneğidir.

Colophon: "Const answer" onay işaretini veriyorum çünkü bunun yapılması gerekebileceğinin gerçek bir sebebi; ancak, ANSI C öncesi bir özel (en azından bazı programcılar arasında) olmasının cevabı, benim durumumda kullanılmasının nedeni gibi görünüyor. Burada birçok kişi tarafından iyi noktalar. Katkılarınız için teşekkür ederiz.


13
"Veri tipini boşaltmadan hemen önce kendimize hatırlatmanın anlamı nedir?" Belki ne kadar bellek boşaltılacağını bilmek ister misiniz?
m0skit0

12
@Codor Derleyici bölmeyi yapmaz, işletim sistemi yapar.
m0skit0

20
@ m0skit0 "Belki ne kadar bellek boşaltılacağını bilmek ister misiniz?" Ne kadar özgür olacağını bilmek için tür gerekli değildir. Bu nedenle sadece kötü kodlama yapılır.
user694733

9
@ m0skit0 Okunabilirlik için döküm her zaman kötü kodlamadır, çünkü döküm türlerin yorumlanma şeklini değiştirir ve ciddi hataları gizleyebilir. Okunabilirlik gerektiğinde yorumlar daha iyidir.
user694733

66
Dinozorların yeryüzünde yürüdüğü ve programlama kitapları yazdığı eski günlerde, void*standart C'de hiç olmadığına inanıyorum , sadece char*. Arkeolojik bulgularınız parametrenin free () 'ye döküm kodunu ortaya çıkarırsa, ya o zaman diliminden ya da o zamandan bir yaratık tarafından yazılmış olması gerektiğine inanıyorum. Bunun için herhangi bir kaynak bulamıyorum, bu yüzden cevap vermekten kaçınırım.
Lundin

Yanıtlar:


171

Eğer işaretçiler varsa derleyici uyarılarını çözmek için döküm gerekebilir const. İşte ücretsiz argümanı yayınlamadan uyarı veren bir kod örneği:

const float* velocity = malloc(2*sizeof(float));
free(velocity);

Ve derleyici (gcc 4.8.3) diyor ki:

main.c: In function main’:
main.c:9:5: warning: passing argument 1 of free discards const qualifier from pointer target type [enabled by default]
     free(velocity);
     ^
In file included from main.c:2:0:
/usr/include/stdlib.h:482:13: note: expected void *’ but argument is of type const float *’
 extern void free (void *__ptr) __THROW;

Eğer free((float*) velocity);derleyici kullanırsanız şikayet durur.


2
@ m0skit0 bu, birisinin float*özgürleşmeden önce neden yayınlanacağını açıklamaz . free((void *)velocity);Gcc 4.8.3 ile denedim . Tabii ki eski bir derleyici ile çalışmaz
Manos Nikolaidis

54
Peki neden sabit belleği dinamik olarak ayırmanız gerekiyor? Asla kullanamazsın!
Nils_M

33
@Nils_M Bir noktaya değinmek basitleştirilmiş bir örnektir. Bir fonksiyonda gerçek kodda ne yaptım const olmayan bellek ayırmak, değerleri atamak, bir const işaretçisine döküm ve geri. Şimdi, önceden atanmış sabit belleğe birisinin boşaltması gereken bir işaretçi var.
Manos Nikolaidis

2
Örnek : “Bu alt yordamlar, dizeyi, sonunda serbest bırakmanız gereken * stringValueP ile gösterilen yeni hatalı bellekte döndürür. Bazen, belleği boşaltmak için kullandığınız OS işlevinin argümanı olarak sabit olmayan bir şeye işaretçi aldığı bildirilir, bu nedenle * stringValueP bir sabitin işaretçisi olduğundan. ”
Carsten S

3
Bir işlev alırsa Hatalı, const char *pbir argüman olarak ve sonra serbest bırakır, yapılacak doğru şey döküm değil piçin char*ücretsiz çağırmadan önce. Bu alarak olarak ilan değil içelim const char *po zamandan beri, ilk etapta değiştirir *p ve buna göre ilan edilmelidir. (Yerine const göstericinin bir const işaretçi alır eğer, int *const p, sen yok gerek aslında yasal ve böylece döküm olmadan cezası çalıştığı için döküm için.)
Ray

59

Ön standart C hiçbir vardı void*ama sadece char*sen iletilen tüm parametreleri döküm zorunda. Eski C koduyla karşılaşırsanız, bu nedenle bu tür dökümleri bulabilirsiniz.

Referanslar ile benzer bir soru .

İlk C standart yayımlandığında, malloc ve ücretsiz olarak prototipleri sahip olmaktan değişti char*için void*hala bugün sahip oldukları.

Ve elbette standart C'de, bu tür dökümler gereksizdir ve sadece okunabilirliğe zarar verir.


23
Peki neden bu argümanı freehalihazırdakiyle aynı tipte gösteresiniz?
jwodder

4
@chux Ön standartla ilgili sorun sadece şudur: hiçbir şey için herhangi bir yükümlülük yoktur. İnsanlar kanon için K&R kitabını işaret ettiler çünkü sahip oldukları tek şey buydu. K&R 2. baskıdaki çeşitli örneklerden de görebildiğimiz gibi, K&R'nin kendisinin parametrenin freestandart C'de nasıl çalışacağı konusunda kafa karıştırması gerekir (döküm yapmanıza gerek yoktur). 1. baskıyı okumadım, bu yüzden 80'lerin standart öncesi zamanlarda da karışık olup olmadıklarını söyleyemem.
Lundin

7
Standart öncesi C yoktu void*, ancak fonksiyon prototipleri de yoktu, bu nedenle freeK&R'de bile argümanı yayınlamak hala gerekli değildi (tüm veri işaretçisi türlerinin aynı temsili kullandığını varsayarak).
Ian Abbott

6
Zaten yorumlarda belirtilen birçok nedenden dolayı, bu cevabın mantıklı olduğunu düşünmüyorum.
R .. GitHub BUZA YARDIMCI DURDUR

4
Bu cevabın gerçekten alakalı her şeye nasıl cevap vereceğini görmüyorum. Orijinal soru, sadece diğerlerine değil, başka türlere de yayınlar içerir char *. Eski derleyicilerde ne anlam ifade ederdi void? Bu tür oyuncular ne elde eder?
AnT

34

İşte özgür oyuncu kadrosu olmadan başarısız olacak bir örnek:

volatile int* p = (volatile int*)malloc(5 * sizeof(int));
free(p);        // fail: warning C4090: 'function' : different 'volatile' qualifiers
free((int*)p);  // success :)
free((void*)p); // success :)

C'de bir uyarı alabilirsiniz (VS2012'de bir tane var). C ++ ile hata alırsınız.

Nadir durumlarda, döküm sadece kodu şişiriyor ...

Düzenleme: Ben başarısızlık demo void*değil döküm int*. Örtük int*olarak dönüştürülecekle aynı şekilde çalışacaktır void*. int*Kod eklendi .


Soruda yayınlanan kodda, atmaların değil void *, float *ve için olduğunu unutmayın char *. Bu oyuncular sadece yabancı değil, yanılıyorlar.
Andrew Henle

1
Soru aslında bunun tam tersi.
m0skit0

1
Cevabı anlamıyorum; hangi anlamda free(p)başarısız olur? Derleyici hatası verir mi?
Codor

1
Bunlar iyi noktalar. Aynısı constniteleyici işaretçiler için de geçerlidir .
Lundin

2
volatileC artık uzun değilse standartlaştırıldığından beri var olmuştur. O oldu değil C99 eklendi.
R .. GitHub DUR YARDIMCI ICE

30

Eski sebep: 1. kullanarak free((sometype*) ptr), işaretçi free()çağrının bir parçası olarak kabul edilmesi gereken tür hakkında kod açıktır . Açık döküm, free()bir (kendin yap) ile değiştirildiğinde yararlıdır DIY_free().

#define free(ptr) DIY_free(ptr, sizeof (*ptr))

A DIY_free(), özellikle hata ayıklama modunda, serbest bırakılan işaretçinin çalışma zamanı analizini yapmanın bir yoluydu. Bu genellikle bir DIY_malloc()cümle, küresel bellek kullanım sayısı, vb. Eklemek için eşleştirilir. Grubum, daha modern araçlar görünmeden önce bu tekniği yıllarca kullandı. Serbest bırakılan öğenin türüne aktarılması zorunlu olarak tahsis edildi.

  1. Bellek sorunlarını, vb. İzlemek için harcanan uzun saatler göz önüne alındığında, türü serbest bırakmak gibi küçük hileler hata ayıklamanın aranmasına ve daraltılmasına yardımcı olacaktır.

Modern: Manos Nikolaidis @ ve @egur tarafından ele alındığı gibi kaçınma constve volatileuyarılar . Düşünce Ben 3 etkilerini dikkate olur elemeleri : , , ve .constvolatilerestrict

Eklenen [değiştir] char * restrict *rp2başına @R .. comment

void free_test(const char *cp, volatile char *vp, char * restrict rp, 
    char * restrict *rp2) {
  free(cp);  // warning
  free(vp);  // warning
  free(rp);  // OK
  free(rp2);  // warning
}

int main(void) {
  free_test(0,0,0,0);
  return 0;
}

3
restrictyalnızca yerleştirildiği yer nedeniyle sorun rpdeğildir - sivri uçlu nesneyi etkilemez . Yerine sahip char *restrict *rpolsaydınız, önemli olurdu.
R .. GitHub BUZA YARDIMCI DURDUR

16

İşte başka bir alternatif hipotez.

Programın C89 öncesi yazıldığı söyleniyor, bu da prototipiyle bir tür uyumsuzluk etrafında çalışamayacağı anlamına geliyor free, çünkü sadece C89 gibi bir şey constya da void *öncesi gibi bir şey yoktu. C89'dan önceki bir fonksiyon prototipi . stdlib.hkendisi komitenin bir buluşuydu. Sistem başlıkları freehiç beyan etmekten rahatsız olsaydı, bunu şu şekilde yaparlardı :

extern free();  /* no `void` return type either! */

Şimdi, buradaki kilit nokta, fonksiyon prototiplerinin yokluğunun, derleyicinin argüman tipi kontrolü yapmadığı anlamına gelmesidir . Varsayılan argüman promosyonlarını (varyasyon fonksiyon çağrıları için hala geçerli olanlar) uyguladı ve hepsi bu. Her çağrı sahasındaki argümanları callee'nin beklentileriyle örtüştürme sorumluluğu tamamen programcıya aittir .

Bununla birlikte, bu hala tartışmayı freeçoğu K&R derleyicisine atmanın gerekli olduğu anlamına gelmez . Gibi bir işlev

free_stuff(a, b, c)
    float *a;
    char *b;
    int *c;
{
    free(a);
    free(b);
    free(c);
}

doğru derlenmiş olmalıdır. Örneğin, bir ortam: Ne biz burada var alışılmadık çevre için bir arabası derleyici ile başa çıkmak için yazılmış bir programdır düşünüyorum Yani sizeof(float *) > sizeof(int)derleyici ve olmaz sen noktada onları döküm sürece göstericiler için uygun çağrıdüzenini kullanmak çağrı.

Böyle bir ortamın farkında değilim, ama bu bir ortam olmadığı anlamına gelmez. Akla gelen en muhtemel adaylar, 1980'lerin başında 8- ve 16-bit mikronlar için "küçük C" derleyicileri kesti. Erken Crays'in böyle problemleri olduğunu öğrenmek beni şaşırtmaz.


1
İlk yarıya tamamen katılıyorum. Ve 2. yarı ilginç ve makul bir varsayımdır.
chux - Monica'yı

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.