Neden ücretsiz geri dönüş değerini geçersiz kılar?


82

C kullanan bir kitap okuyorum ( POSIX Threads tarafından Programlama, Butenhof, 1997) ve aşağıdaki satırla karşılaştım:

(void)free(data);

Burada, datatahsis edilmiş bir yapıya sadece bir işaretçi,

data = malloc(sizeof(my_struct_t));

Neden sonucudur freeiçin dışlandığımdı void?

C anlayışımdan, bu iki nedenden dolayı mantıklı görünmüyor:

  • Serbest işlev zaten geri döner void
  • Kod dönüş değerini kullanmıyor (bir değişkene atanmıyor bile)

Kitap 1997'de yazıldı. Bu bir tür miras mı?

Yazar, örneklerin Digital Unix 4.0d'de çalıştırıldığından bahsediyor, ancak yine de bu sonucu kullanmayacaksanız bir işlevin sonucunu yayınlamak için bir neden hayal bile edemiyorum.


Bazı olası açıklamalar burada bulunabilir: stackoverflow.com/questions/689677/…
Timbo

3
Meraktan, C kitabınızın yayınlanma tarihi nedir? (Hangi kitap bu?) 1995'ten önce ise, bunun bir gerekçesi olabilir - standart C derleyicileri o zamandan beri her yerde her yerde bulunmuyordu. Bundan sonra yayınlanıyorsa ve hala kadroyu içeriyorsa (ve nedenini açıklamıyorsa), size hangi kötü alışkanlıkları öğrettiğinden endişe edin. Daha yeni bir kitap edinin!
Jonathan Leffler


3
@JonathanLeffler orijinal yazımda belirtildiği gibi, kitap 1997 yılında yayınlandı ve UNIX 4.0d kullanıyordu. Kitap David R. Butenhof'un "POSIX Konuları ile Programlama" dır. Şimdiye kadar çok bilgilendirici olmuştur ve POSIX iş parçacığı standardına ilk katkıda bulunanlardan biri tarafından yazılmıştır.
Adam Johnston

6
Geçen hafta bunun kopyasını kullanıyorum - evet, hala kullanışlı. “Yaygın C standardı” nezdinde yazılmıştır ('1995 hakkında' dedim). 'UNIX 4.0d' Dijital UNIX gibi geliyor - Butenhof burada çalışıyordu ve önsöz bundan bahsediyor. Üzerinde döküm Treat free()taklit etmek gerekmez o kitapta bir gariplik olarak. Uzun zaman önce bir kez yarı alakalı, ama artık geçerli değil.
Jonathan Leffler

Yanıtlar:


100

Standart freeişlevden bahsediyorsak , prototipi

void free(void *ptr);

Bu nedenle oyuncular tamamen işe yaramaz.
Şimdi bazı spekülasyonlar.

Yazar stdlib.h, bu prototipi bildiren başlığı eklemeyi unutmuş olabilir , bu nedenle derleyici dönüş türünü varsayılan olarak kabul eder int. Şimdi bu kodun statik analizi sırasında, derleyici işlevsiz olduğunu düşündüğü şeyin kullanılmayan dönüş değeri hakkında uyarı veriyordu void. Bu tür uyarılar genellikle oyuncu kadrosuna eklenerek susturulur void.


50
Ancak, oyuncu öngörülen nedenden ötürü tanıtıldıysa, sessizleştirmek için kullanmanın uyarının yanlış olduğunu unutmayın . Derleyici, bu durumda free, gerçekte olduğundan farklı bir türle ilişkilendirilir ve bunun sonucu olarak çağrının tanımlanmamış davranışı olur (bildirilmemiş bir işlevi çağırmanın her durumda UB'yi göstermediği C90 anlambilimi varsayalım). Uygulamada, bunun bazı sistemlerde iyi niyetli yanlış davranışlara yol açması mantıklıdır . Doğru çözüm, işlev için doğru bir bildirim sağlamaktır.
John Bollinger

11
Özellikle, "POSIX İş Parçacıklarıyla Programlama" daki örnekler tekrar tekrar ilgili standart başlıkları içermez. Belki de bu yazar tarafından kötü bir uygulamadır, varsayılan olarak tüm standart kütüphaneleri içeren standart olmayan bir derleyici kurulumu kullanıyor olabilirlerdi.
Lundin

74

Bu eski bir şey olurdu!

Bir C standardı olmadan önce, free()işlev (dolaylı olarak) türden olurdu int- çünkü voidgeri dönmesi için henüz güvenilir bir tür yoktu. Hiçbir değer döndürülmedi.

Kod, standart C derleyicileriyle çalışmak üzere ilk kez değiştirildiğinde, muhtemelen içermiyordu <stdlib.h>(çünkü standarttan önce yoktu). Eski kod yazardı extern char *malloc();(belki olmadan externtahsis fonksiyonları (benzer için için) calloc()ve realloc()) ve bir açıklamadan gerek yoktu free(). Ve kod daha sonra dönüş değerini doğru türe çevirir - çünkü bu en azından bazı sistemlerde gerekliydi (C'yi öğrendiğim sistem dahil).

Bir süre sonra, bir şikayetten kaçınmak (void)için derleyiciye (veya daha büyük olasılıkla lint) "gelen dönüş değerinin free()kasıtlı olarak göz ardı edildiğini" söylemek için oyuncu kadrosu eklendi . Ancak <stdlib.h>, beyanını veya derleyiciyi görmezden gelmenin bir değeri olmadığını extern void free(void *vp);söylemek ve eklemek daha iyi olurdu lint.

JFTR: 80'lerin ortalarında, ICL Perq başlangıçta bir kelime odaklı mimari üzerindeydi ve char *bir bellek konumunun adresi, 'her şey_seç işaretçisinden' aynı konuma çok farklı bir rakamdı . Bir char *malloc()şekilde beyan etmek çok önemliydi ; sonucun başka bir işaretçi türüne dökülmesi çok önemliydi. Oyuncular aslında CPU tarafından kullanılan sayıyı değiştirdi. (Sistemlerimizdeki ana bellek 1 MiB'den 2 MiB'ye yükseltildiğinde de çok sevindi - çekirdek yaklaşık 3/4 MiB kullandığı için, kullanıcı programlarının çağrı yapmadan önce 1 1/4 MiB kullanabileceği anlamına geliyordu.)


9
Az önce K & R'nin 1. baskısının bir kopyasını açtım free(). 177 dolaylı olarak geri döner int.
eski nihilo

9
Tabii ki - voidstandart yayınlanmadan önce bazı sistemlere (belki de Unix System III) eklendi, ancak K&R 1st Edn (1978) yazıldığında bu C'nin bir parçası değildi. Bir değer döndürmeyen bir işlev, bir döndürme türü olmadan (geri döndüğü anlamına gelir int) bildirildi ve döndürülmeyen değeri kullanmadığınız sürece sorun olmadı. C90 standardı bu tür bir kodu geçerli olarak ele almak zorundaydı - bir standartın sahip olmadığı gibi kötü bir şekilde başarısız olurdu. Ancak C99, 'örtük int' ve 'örtük işlev bildirimi' kurallarını kaldırdı . Dünyadaki tüm kodlar yakalanmadı.
Jonathan Leffler

5
Op, kitabın 1997'de yazıldığını iddia ediyor. Burada bahsettiğiniz şey çok erken bir standart öncesi "K&R C" dir ve herkesin bu konuda bir kitap yazması pek olası görünmemektedir. Bildiğim kadarıyla böyle bir kitap gerçekten de K&R 1. basımdı.
Lundin

Örtülü bildirimden kurtulabileceğinizi düşündüğünüzde başlıkları dahil etmemek sıkça yapılan (quixotic ise) bir uygulamadır, çünkü insanlar bunun oluşturma sürelerini azaltacağını düşündü.
Spencer

Herkes (void)alçı kullanıyor mu printf()??
Luis Colorado

11

Bu oyuncu kadrosuna gerek yok. C, C89 şeklinde standartlaştırıldığı için muhtemelen o zaman olmazdı.

Eğer olsaydı, dolaylı bir beyandan dolayı olurdu . Bu genellikle kodu yazan kişinin unuttuğu #include <stdlib.h>ve statik bir analizörün kullanıldığı anlamına geliyordu . Bu en iyi geçici çözüm değildir ve #include <stdlib.h>bunun yerine daha iyi bir fikir olurdu . İşte C89'dan örtülü bildirimle ilgili bazı ifadeler:

Bir işlev çağrısında parantez içindeki bağımsız değişken listesinden önce gelen ifade yalnızca bir tanımlayıcıdan oluşuyorsa ve bu tanımlayıcı için hiçbir bildirim görünmüyorsa, tanımlayıcı tam olarak, işlev çağrısını içeren en içteki blokta, bildirim olarak örtük olarak bildirilir.

extern int identifier();

ortaya çıktı.

Ama bu garip çünkü mallocikisinin de sonucunu vermiyorlar ve mallocvefree aynı başlık dosyasında bulunmaktadır.

Bunun sadece bir hata veya okuyucuya freesonuç vermediğini söylemenin bir yolu olması da mümkündür .


5
Bir dilin standartlaştırılması, herkesin araç zincirini ve kodunu anında ona uygun şekilde güncellediği anlamına gelmez. Eski tarz "K&R" C'nin 8 yıl daha takılmış olması akla yatkındır. Yine de, statik bir analiz aracının bir döküm gerektirdiğini, freeancak istemediğini tuhaf buluyorum malloc.
dan04

4
@ dan04 Genellikle malloc'un sonucunu kullanırsınız;) Derleyicinin uyarı tükürmesini durdurmak için (void) printf (...) gibi şeyler yazmanın hayranı değilim ama "herhangi bir uyarı olmadan, aptal olanlar bile derlemelisiniz" bir çok projede oluyor.
richardb
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.