Bu kod neden 64 bit mimaride segfault, ancak 32 bit üzerinde iyi çalışıyor?


112

Aşağıdaki C bulmacasıyla karşılaştım:

S: Aşağıdaki program neden IA-64'e ayrılıyor, ancak IA-32'de iyi çalışıyor?

  int main()
  {
      int* p;
      p = (int*)malloc(sizeof(int));
      *p = 10;
      return 0;
  }

int64 bitlik bir makinedeki boyutunun bir göstericinin boyutuyla aynı olmayabileceğini biliyorum ( int32 bit ve işaretçi 64 bit olabilir). Ancak bunun yukarıdaki programla nasıl bir ilgisi olduğundan emin değilim. Herhangi bir fikir?


50
stdlib.hDahil edilmemek gibi aptalca bir şey mi?
user786653

3
Bu kod 64 bit makinemde iyi çalışıyor. Hatta siz #include stdlib.h(malloc için) uyarısı olmadan derler
mpenkov

1
D'oh! @ user786653 önemli bir kısmı yakaladı. İle #include <stdlib.h>, mükemmel bir şekilde bulun, ama söz konusu değil.

8
@delnan - böyle çalışması gerekmiyor, ancak sizeof(int) == sizeof(int*)örneğin işaretçilerin intkullanılan arama kuralındaki s'ye farklı bir kayıt olmasına rağmen geri döndüğü bir platformda yasal olarak başarısız olabilir .
Flexo

7
Bir C99 ortamında, derleyicinin size en azından örtük bildirimi hakkında bir uyarı vermesi gerekir malloc(). GCC diyor ki: warning: incompatible implicit declaration of built-in function 'malloc'çok.
Jonathan Leffler

Yanıtlar:


130

Oyuncular int*, uygun olmayan#include dönüş türünün mallocvarsayıldığı maskeliyor int. IA-64'ün olması sizeof(int) < sizeof(int*)bu sorunu bariz kılıyor.

(Ayrıca, tanımlanmamış davranış nedeniyle sizeof(int)==sizeof(int*), doğru olduğu bir platformda bile başarısız olabileceğini unutmayın , örneğin, çağıran kural tamsayılardan ziyade işaretçileri döndürmek için farklı yazmaçlar kullanırsa)

Comp.lang.c SSS tartışan bir girdi dan dönüşü döküm neden mallocgerekli ve potansiyel olarak kötü asla .


5
uygun #include olmadan, neden malloc'un dönüş türünün int olduğu varsayılıyor?
kullanıcı7

11
@WTP - bu, her zaman newC ++ 'da kullanmak ve her zaman C'yi bir C ++ derleyicisi ile değil bir C derleyicisiyle derlemek için iyi bir nedendir .
Flexo

6
@ user7 - kurallar budur. intBilinmiyorsa herhangi bir iade türünün olduğu varsayılır
Flekso

2
@vlad - daha iyi fikir, tam da bu nedenle örtük bildirimlere güvenmek yerine her zaman işlevleri bildirmektir. (Ve dönüşü malloc
atmayın

16
@ user7: "32 bit belleğe işaret eden p (64 boyutunda) işaretçisine sahibiz" - yanlış. Malloc tarafından ayrılan bloğun adresi, bir void*. Ancak çağıran kod, işlevin geri döndüğünü düşünür int(siz ona aksini söylememeyi tercih ettiğiniz için), bu nedenle dönüş değerini an için çağırma kuralına göre okumaya çalışır int. Bu nedenle , ayrılan belleğe işaret etmek pzorunda değildir . IA32 için işe yaradı çünkü an intve a void*aynı boyutta ve aynı şekilde geri döndü. IA64'te yanlış değeri alıyorsunuz.
Steve Jessop

33

Büyük olasılıkla başlık dosyasını dahil etmediğiniz içinmalloc ve derleyici normalde sizi bu konuda uyarırken, dönüş değerini açıkça atıyor olmanız, ona ne yaptığınızı bildiğinizi söylediğiniz anlamına gelir.

Araçlarının derleyici bekler intdöndürülecekmalloc daha sonra bir işaretçi atan olan. Farklı boyutlardalarsa, bu üzülmenize neden olur.

Bu yüzden C'ye dönüşü asla atmazsınız. Döndüğü şey dolaylı olarak doğru tipte bir göstericiye dönüştürülür (başlığı dahil etmediyseniz, bu durumda muhtemelen sizi potansiyel olarak güvenli olmayan int- işaretçi dönüştürme).mallocvoid*


saf göründüğüm için özür dilerim, ancak malloc'un uygun bir türe dönüştürülebilecek bir boşluk gösterici döndürdüğünü her zaman varsaydım. Ben bir C programcısı değilim ve bu nedenle biraz daha ayrıntıya değer veririm.
kullanıcı7

5
@ user7: #include <stdlib.h> olmadan C derleyicisi malloc'un dönüş değerinin bir int olduğunu varsayar.
sashang

4
@ user7: void işaretçi olabilir olarak C döküm, ancak gerekli değil void *örtülü başka işaretçi türüne dönüştürülebilir. int *p = malloc(sizeof(int))uygun prototip kapsam dahilindeyse çalışır ve değilse başarısız olur (çünkü sonucun olduğu varsayılır int). Cast ile, her ikisi de derlenir ve ikincisi ne zaman hatalara neden olur sizeof(int) != sizeof(void *).

2
@ user7 Ancak dahil etmezseniz stdlib.h, derleyici mallocne de dönüş türünü bilmez . Bu yüzden varsayılan intolarak varsayılır.
Christian Rau

10

Bu nedenle, eksik prototipler hakkında uyarılar olmadan asla derleme yapmazsınız.

Bu yüzden C'de malloc dönüşünü asla yapmadınız.

Döküm, C ++ uyumluluğu için gereklidir. Bunu atlamak için çok az neden (okuyun: burada bir neden yok) var.

C ++ uyumluluğu her zaman gerekli değildir ve bazı durumlarda hiç de mümkün değildir, ancak çoğu durumda çok kolay bir şekilde elde edilir.


22
C kodumun C ++ ile "uyumlu" olmasını neden umursayayım? Perl, java veya Eiffel ile uyumlu olması umurumda değil veya ...
Stephen Canon

4
Sıradaki birinin C kodunuza bakmayacağını garanti ediyorsanız, bunu bir C ++ derleyicisiyle derleyeceğim çünkü işe yaramalı!
Steven Lu

3
Bunun nedeni, çoğu C kodunun önemsiz bir şekilde C ++ uyumlu hale getirilebilmesidir.
curiousguy
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.