Malloc nəticəsini yazdırın?

Bu sualda , kimsə malloc nəticəsinə malloc lazım olduğunu şərh etdi, yəni.

 int *sieve = malloc(sizeof(int) * length); 

və deyil:

 int *sieve = (int *) malloc(sizeof(int) * length); 

Niyə belədir?

2149
03 марта '09 в 13:13 2009-03-03 13:13 Patrick McDonald Mart 03 '09' da 13:13 'də soruşdu. 2009-03-03 13:13
@ 28 cavab

Xeyr ; Nəticəni tələffüz etmirsiniz, çünki:

  • Bu, isteğe bağlıdır, çünki bu halda void * avtomatik olaraq və təhlükəsiz olaraq hər hansı digər tip göstəriciyə keçər.
  • Koda qarışıqlıq əlavə edir, tökmə oxumaq çox asan deyil (xüsusilə pointer növü uzun olduqda).
  • Bu təkrar edir, adətən pisdir.
  • <stdlib.h> daxil etməyi unutduğunuzda səhv gizlədə bilər. Bu, çökmələrə gətirib çıxara bilər (və ya daha da pis, sonunadək kodun tamamilə fərqli bir hissəsinə qədər qəzaya səbəb olmaz). Göstərici və tamsayılar fərqli olduqda nə olacağını düşünün; sonra tökmə ilə xəbərdarlığı gizləyin və geri dönən ünvanınızdan bir az itirərsiniz. Qeyd: C11 ilə örtülü funksiyalar C-dən itmiş və bu nöqtə artıq vacib deyil, çünki bildirilməmiş funksiyaların bir int qaytarılmasına dair avtomatik bir fərziyyə yoxdur.

Bir izahat olaraq qeyd etdiyim ki, "siz çıxmırsınız" və "çıxmaq lazım deyil" deyirəm. Mənim fikrimcə, bu, doğru olsanız da, bu sənədi açmaq mümkün deyil. Bunun üçün sadəcə heç bir üstünlük yoxdur, lakin daxilolma daxil olmaqla bir çox potensial risk risklərdən xəbərdar olmadığınızı göstərir.

Qeyd edək ki, şərhçilər qeyd etdilər ki, C ++ ilə əlaqəli yuxarıda qeyd olunan söhbətlər. C və C ++-ə ayrı-ayrı dillərdə inanıram.

Əlavə etmək üçün kodunuzu lazımsız olaraq ( int ) tipli məlumatları təkrarlayır və bu da səhvlərə səbəb ola bilər. İki birini bir-birinə "dayandırmaq" üçün dönüş dəyərini saxlamaq üçün istifadə olunan göstəricini azaltmaq daha yaxşıdır:

 int *sieve = malloc(length * sizeof *sieve); 

Bu da görünürlüğünü artırmaq üçün length artırır və sizeof əlavə parantezləri azaldır; yalnız arqument bir növü adı olduğunda onlara ehtiyac duyulur. Bir çox insanlar öz kodlarını daha detallı edən bu məlumatı (yaxud görməmişlər) görünmürlər. Unutmayın: sizeof funksiyası deyil! :)


Cəbhəyə doğru hərəkət edərkən görünürlük bəzi nadir hallarda artırıla bilər, ümumi vəziyyətdə belə bir ifadə yazmaq daha yaxşıdır:

 int *sieve = malloc(sizeof *sieve * length); 

Əvvəlcə sizeof saxlayandan bəri, bu halda, ən azı size_t matematikası ilə çarpma həyata keçirilir.

Müqayisə et: malloc(sizeof *sieve * length * width) vs İkinci malloc(length * width * sizeof *sieve) width lengthsize_t dən daha kiçik olduqda, length * width size_t .

2003
03 марта '09 в 13:17 2009-03-03 13:17 cavab 03.03 'də saat 13:17' də açılacaqdır. 2009-03-03 13:17

C'de, malloc qaytarma dəyərini təyin etmək lazım deyil. malloc tərəfindən qaytarılan malloc bir göstərici avtomatik olaraq doğru tipə çevrilir. Bununla belə, kodunuzu C ++ tərtibatçısı ilə tərtib etmək istəyirsinizsə, tökmə etmək lazımdır. Cəmiyyət üçün üstünlük verilən alternativ aşağıdakılardan istifadə etməkdir:

 int *sieve = malloc(sizeof *sieve * length); 
border=0

sieve növünü dəyişdirirsinizsə, bir ifadəin sağ tərəfini dəyişdirməkdən narahat olmaqdan azad edir.

Xalqlar tərəfindən göstərildiyi kimi, kastlar pisdir. Xüsusi örtülü göstərici.

338
03 марта '09 в 13:17 2009-03-03 13:17 cavab 03/09/03 saat 13:17 'də dəhşətli şəkildə verilir. 2009-03-03 13:17

Çünki:

  • Bu sizin kodunuzu C və C ++ arasında daha portativ edir və SO təcrübəsi göstərir ki, bir çox proqramçı C ++ (ya da yerli C kompilyatoru plus uzantıları) yazdıqda C yazdıqlarını iddia edirlər.
  • Bunu etməməsi səhvləri gizlədə bilər : type * type ** yazarkən bütün SO-obfuscation nümunələrini qeyd edin.
  • Sizə uyğun olmayan başlıq faylını daxil edə #include imkan vermədiyi ideyası ağaclar üçün meşə atlayır. Bu deyərək eyni deyilir: "Prototipləri görməməyinizdən şikayətçi olmamanızdan narahat olmadığınız üçün narahatçılığa çəkməyin - bu zəhlətökən stdlib.h yadda saxlamaq vacibdir!"
  • Əlavə kognitiv cross-validation gücləndirir. Bu dəyişənin xammal ölçüsü üçün etdiyiniz aritmetikin yanında təxmin edilən istənilən növü qoyur. Mən bir roll var zaman malloc() səhvləri daha sürətli tutulduğunu göstərir ki, bir SO tədqiqat edə bilərsiniz bahis. Təsəvvürlərdə olduğu kimi, niyyət göstərən notları da səhvlərin sayını azaldır.
  • Bir maşın test edə biləcək bir şəkildə özünüzü təkrarlayan bir fikirdir. Əslində, bəyanat nədir və aktyorların bu istifadəsi bir bəyanatdır. Turing bu fikri bir çox il əvvəl ortaya qoyduğundan, iddialar doğru kod üçün hələ də ən çox yayılmış texnikadır.
306
14 февр. Ron Burk tərəfindən verilmiş cavab 14 fevral. 2013-02-14 19:15 '13 saat 19:15 'da 2013-02-14 19:15

Göstərildiyi kimi, C üçün lazım deyil, C ++ üçün. C ++ tərtibatçısı ilə C kodunuzu tərtib edəcəyinizi düşünürsünüzsə, nədənsə makroyu istifadə edə bilərsiniz:

 #ifdef __cplusplus # define NEW(type, count) ((type *)calloc(count, sizeof(type))) #else # define NEW(type, count) (calloc(count, sizeof(type))) #endif 

Buna görə də hələ çox kompakt yaza bilərsiniz:

 int *sieve = NEW(int, 1); 

və C və C ++ üçün tərtib olunacaq.

155
03 марта '09 в 14:17 2009-03-03 14:17 03.03 'də 03.03 ' da qəhqəhələr tərəfindən verilən cavab 2009-03-03 14:17

Vikipediyadan

Dökümün üstünlükləri

  • Bir rol daxil olmaqla C proqramını və ya funksiyasını C ++ kimi tərtib etməyə icazə verə bilər.

  • Listinq 1989-cu ilə qədər malloc versiyalarına imkan verir, əvvəlcə char * tərəfindən qaytarılır.

  • Döküm, geliştiriciye, hedef işaretçisinin növü değiştiğinde, xüsusilə işaretçi malloc () çağırışından uzaqlaşdıysa (baxmayaraq ki, müasir derleyiciler ve statik analizörler döküm olmadan bu davranışı xəbərdar edə bilərlər), bu türdeki tutarsızlıkları belirlemeye kömək edə bilər.

Tökmə Dezavantajları

  • ANSI C standartında döküm lazımsızdır.

  • Bir rolu əlavə etmək, malloc prototipinin tapıldığı stdlib.h başlığının daxil edilməməsi uğursuzluğunu maskara bilər. Malloc üçün prototip olmadıqda, standart C kompilyatorunun mallocun bir int qaytarılmasını tələb edir. Süzgəc yoxdursa, göstərici tam sayına təyin edildikdə bir xəbərdarlıq verilir; Lakin, bir atışla, bu xəbərdarlıq səhv gizlənərək yaranmır. Belirli bir malloc 32-bit dəyərini qaytarır, çünki müəyyən mimariler ve veri modellərində (məsələn, 64-bit sistemlərdə uzun və 64-bit göstəricilər və 32-bit int) LP64, bu səhv, həqiqətən, müəyyən edilməmiş davranışa səbəb ola bilər, əslində müəyyən edilmiş funksiya 64 bit dəyər verir. Çağırış konvensiyalarına və layout yaddaşına görə, bu, bir yığın fasilə gətirə bilər. Bu sual, müasir kompilyatorlarda nəzərəçarpan bir vəziyyətə düşməyəcəkdir, çünki onlar eyni zamanda bildirilməmiş bir funksiyanın tətbiq olunduğunu xəbərdar edir, belə ki, xəbərdarlıqlar hələ də görünəcəkdir. Məsələn, GCC'nin default davranışı, bir dökümün var olub olmadığına bakılmaksızın, "Daxili bir funksiyanın uyğunsuz örtülü bildirimi" deyən bir uyarıyı göstermektir.

  • Göstərici tipi elan edildikdə dəyişirsə, mallocun çağırıldığı və yerinə yetirildiyi bütün satırları dəyişə bilərsiniz.

Qeyri-döküm mallocu üstünlük təşkil edirsə və ən təcrübəli proqramçılar onu seçsələr də, problemlər haqqında bilmək istədiyinizi istifadə etməlisiniz.

yəni: C ++ kimi bir C proqramı tərtib etməlisiniz (bu ayrı bir dil olsa da), döküm ilə malloc istifadə etməlisiniz.

107
10 окт. cavab ashiquzzaman33 10 oct verilir . 2015-10-10 00:23 '15 at 0:23 2015-10-10 00:23

C'de, bir boş göstəricini hər hansı digər göstəriciyə dolayı çevirə bilərsiniz, belə ki, tökmə tələb olunmur. Biri istifadə edərək, təsadüfi müşahidəçi üçün birinin tələb olunduğu bir səbəbin olduğunu və yanıltıcı ola biləcəyini təklif edə bilərsiniz.

96
03 марта '09 в 13:18 2009-03-03 13:18 Cavab PaulJWilliams tərəfindən 03.03 'də 03.03 ' də verildi

Siz mallocun nəticəsini tələffüz etmirsiniz, çünki kodunuza faydasız bir qarışıqlıq əlavə edir.

İnsanlar mallocun nəticəsini ən çox yaymaq səbəbi C dilinin necə işlədiyindən əmin deyildir. Bu bir xəbərdarlıq əlaməti: əgər müəyyən bir dil mexanizminin necə işlədiyini bilmirsinizsə, fərziyyələr verməyin. Bunu yoxlayın və ya yığın taşması haqqında soruşun.

Bəzi şərhlər:

  • A boş göstərici açıq döküm olmadan (C11 6.3.2.3 və 6.5.16.1) hər hansı digər pointer növünə çevrilə bilər.

  • Bununla belə, C ++ void* və digər göstərici tipi arasında gizli transfer etməyə imkan vermir. Beləliklə, C ++ da, cast doğru olacaq. Lakin C ++ 'da proqramlaşdırma edirsinizsə, malloc () deyil, new istifadə etməlisiniz. C kodunu C ++ kompilyatoru ilə heç vaxt tərtib etməməlisiniz.

    Eyni qaynaq koduyla C və C ++ həm dəstəkləməlisiniz, fərqləri qeyd etmək üçün derleyici keçidlərindən istifadə edin. Həm yerli kodları eyni kodla təmin etməyə çalışmayın, çünki onlar uyğunsuzdur.

  • C cədvəlinin başlığı daxil etməyi unutduğunuz üçün funksiyanı tapa bilmirsinizsə, bir derleyici / bağlayıcı hata mesajı alırsınız. Buna görə də, <stdlib.h> daxil etməyi unutduğunuz halda, heç bir şey yoxdur, öz proqramınızı yarada bilməyəcəksiniz.

  • 25 yaşdan yuxarı olan standart versiyanı təqib edən qədim kompilyatorlarda <stdlib.h> daxil etməyi unutma təhlükəli davranışa səbəb olacaq. Çünki bu qədim standartda görünən prototipsiz funksiyalar örtük olaraq int növünə int çevrilir. Malloc-dan nəticə çıxarmaq bu xətanı gizlədir.

    Amma bu həqiqətən problem deyil. 25 yaşındakı bir kompüterdən istifadə etməyin, onda nə üçün 25 yaşlı bir kompilyator istifadə edirsiniz?

87
20 марта '14 в 18:53 2014-03-20 18:53 Cavab Lundin tərəfindən 20 Mart 'da 18:53' də veriləcək 2014-03-20 18:53

C'de, void* hər hansı digər göstəriciyə (məlumatlara) örtülü bir dönüşüm alırsınız.

85
03 марта '09 в 13:16 2009-03-03 13:16 Cavab EFraim tərəfindən 03.03.03 13:16 tarixində verilir

İndi malloc() tərəfindən döndürülen dəyərin dəyəri tələb olunmur, lakin bir nöqtə əlavə etmək istərdim ki, göründüyü kimi heç kim göstərilmədi:

Qədim zamanlarda, yəni ANSI C-dən əvvəl, void * ümumi göstərici növü olaraq char * bu cür istifadə növüdür. Bu halda tökmə kompilyator xəbərdarlıqlarını ləğv edə bilər.

Referans: C Sık Sorulan Sorular

65
09 июня '13 в 20:31 2013-06-09 20:31 Cavab Yu Hao tərəfindən 09.06.2013 20:31 tarixində verilir 2013-06-09 20:31

malloc nəticələrini vermək lazım deyil, çünki bu void* qaytarır void*void* hər hansı bir məlumat növünə işarə edə bilər.

48
08 февр. Cavab user968000 tərəfindən verilir 08 fevral. 2013-02-08 01:22 '13 'da 1:22 2013-02-08 01:22

Kompüter mühəndisliyi ilə məşğul olanda mənim təcrübə əlavə edərək, C-də gördüyüm iki və ya üç professorun həmişə mallocu atdığını görürəm, amma mən soruşduğum biri (C-nin böyük xülasəsi və anlayışı ilə) mənə mütləq lazımsız olduğunu söylədi ancaq tamamilə spesifik olmaq üçün istifadə olunurdu və şagirdləri zehniyyətdə olmaq üçün tamamilə spesifik idi. Əslində, döküm, necə işlədiyini bir şey dəyişdirməyəcəkdir, tam olaraq deyir, yaddaşı ayırır və döküm çəkməyi təsir etmir, eyni yaddaşa sahibsiniz və səhvən çıxarsanız belə və bir şəkildə kompüter səhvindən çəkinməyin). C eyni şəkildə istinad edəcək.

Düzenle: Dökümün müəyyən bir nöqtəsi var. Array notation istifadə edərkən, generated kodu növbəti elementin başlanğıcına çatmaq üçün hərəkətin nə qədər yaddaş olduğunu bilməli, bunun döküm yolu ilə əldə edilməsi lazımdır. Beləliklə, siz bilirsiniz ki, ikiqat irəlidə 8 bayt getmək, int üçün isə 4, Beləliklə, göstərici göstəricisini istifadə edərkən, serial nişanında zəruri olur.

47
28 марта '14 в 21:21 2014-03-28 21:21 Cavab istifadəçi tərəfindən verilir 3079666 28 mart '14 21:21 2014-03-28 21:21

Boşluq göstəricisi ümumi göstəricidir və C göstərici növündən digər növlərə örtülü çevrilməni dəstəkləyir, buna görə dəqiq olaraq dəqiqləşdirilməyə ehtiyac yoxdur.

Bununla belə, əgər eyni kodun C ++ platformasında tam örtüşməsini dəstəkləməyini istəməsinizsə, siz typecasting etməlisiniz, buna görə hər şey mümkünsüzlükdən asılıdır.

28
13 июля '14 в 9:42 2014-07-13 09:42 Cavab Endeavour tərəfindən 13 İyul '14 'də 9:42 2014-07-13 09:42 ' də verilir

GNU C Kitabxanası Reference Guide nədir?

malloc nəticəsini tərcümə olmadan hər hansı bir pointer dəyişəninə saxlaya bilərsiniz, çünki ISO C zəruri hallarda void * tipini başqa bir pointer növünə çevirir. Ancaq tökmə tapşırıq operatorları xaricində bir kontekstdə lazımdır və ya kodunuzun ənənəvi şəkildə işləməsini istəyirsinizsə.

Həqiqətən, ISO standartı C11 (p347) belə deyir:

Göstərici müvəffəqiyyətlə yerinə yetirildiyi təqdirdə qaynaqlanır, belə ki, bir əsas göstəriciyə malik olan obyektin hər hansı bir növünə bir göstəriciyə təyin edilə bilər və sonra bu cür bir obyektə və ya bu cür obyektlərin bir hissəsinə ayrılmış yerə (boşluq açıq şəkildə azad olunana qədər) )

28
09 окт. Cavab Slothworks 09 oktyabr verilir . 2015-10-09 20:47 '15 saat 20:47 'də, 2015-10-09 20:47

Geri qaytarma növü boşdur *, istənilən növdə göstərilən data göstəricisinə təyin edilə bilər.

27
26 апр. Cavab verilmişdir swap 26 apr. 2013-04-26 19:43 '13 at 19:43 2013-04-26 19:43

C'de boş nöqtə hər hansı bir pointerə təyin edilə bilər, belə ki, növü istifadə etməməlisiniz. "Təhlükəsiz növü" ni qeyd etmək istəyirsinizsə, mənim C layihələrimdə həmişə istifadə etdiyim aşağıdakı makroiqtisadiyyatları təklif edə bilərəm:

 #include <stdlib.h> #define NEW_ARRAY(ptr, n) (ptr) = malloc((n) * sizeof *(ptr)) #define NEW(ptr) NEW_ARRAY((ptr), 1) 

Onlarla birlikdə, yalnız deyə bilərsiniz

 NEW_ARRAY(sieve, length); 

Dinamik olmayan dizilər üçün üçüncü zəruri funksiya makro

 #define LEN(arr) (sizeof (arr) / sizeof (arr)[0]) 

array loops daha təhlükəsiz və daha rahat edir:

 int i, a[100]; for (i = 0; i < LEN(a); i++) { ... } 
24
04 сент. Cavab Avqust ayının 04-də verilir . 2015-09-04 14:52 '15 at 14:52 2015-09-04 14:52

Bu proqramlaşdırma dili və kompilyatordan asılıdır. C'de malloc istifadə etsəniz, onu avtomatik olaraq buraxacaqsınız, çünki onu daxil etməyə ehtiyac yoxdur. Lakin, C ++ istifadə edirsinizsə, malloc void* qayıtsın void* .

24
17 марта '14 в 16:16 2014-03-17 16:16 Cavab Ceyamaran tərəfindən 17 mart '14 'də 16:16' də verilir. 2014-03-17 16:16

GCC və C>

Mən illər ərzində inanılmaz tərtib edilmiş kompilyatorlardan istifadə etməmişəm ki, çox qorxdum. Tez-tez şirkətlər və menecerlər dəyişdirən tərtibçilərə ultra mühafizəkar yanaşma tətbiq edir və yeni bir tərtibçinin sistemində olub-olmadığını (daha yaxşı standartlar və kodların optimallaşdırılması) yoxlamayacaq. Işləyicilər üçün praktik reallıq ki, siz kodu yazdığınız zaman bazalarınızı əhatə etməli və təəssüf ki, əla məcburiyyətlər sizin kodunuza hansı kompilyatorun tətbiq oluna biləcəyini nəzarət edə bilməyiniz yaxşı bir vərdidir.

Mən də bir çox təşkilatın öz kodlaşdırma standartlarını tətbiq etdiyini və bu müəyyən edildiyi təqdirdə, insanların izləyəcəyi bir metod olmalıdır. Açıq göstərişlər olmadıqda, standarta bağlılığa sadiq qalmaq deyil, hər yerdə tərtib edirəm.

Hazırkı standartlara uyğun olaraq lazım olmadığı sübut olduqca məqbuldur. Lakin bu arqument real dünyanın praktikliyini saxlayır. Biz günün standartı ilə tənzimlənən dünyada deyil, "yerli idarəetmə səltənəti" adlandırmaq istəmədiyim praktikamızla kodlaşdırmırıq. Və yalnız yerdən daha çox bükülmüş və təhrif edilmişdir: -)

YMMV.

Mən mallocu müdafiə etmə əməliyyatı kimi atmağı düşünürəm. Gözəl deyil, mükəmməl deyil, ümumiyyətlə təhlükəsizdir. (Dürüst, stdlib.h daxil deyilsə, malloc istifadə daha çox problem var!).

14
04 дек. Cavab StephenG 04 dekabrda verilir. 2015-12-04 20:27 '15 at 8:27 pm 2015-12-04 20:27

Köçürülməmiş bir dönüşüm üçün heç bir tərcümənin olmadığı hallarda, diaqnoz olmadan, aşağıda göstərilən fraqment kimi kodu kompilyasiya etməyə imkan verən tip sistemində çirkin çuxurun qəbul edilməməsini göstərmək üçün yalnız cast qoydu:

 double d; void *p =  int *q = p; 

Üzr istəyirəm ki, bu olmadı (və bu C ++ deyil) və buna görə çıxdım. Bu mənim zövqüm və proqramlaşdırma siyasətimdir. Mən göstəriciyi indeksləşdirməklə deyil, həm də bülletenimi effektiv şəkildə tərtib edir və cəfəngiyatdan çıxan cinləri atıram . Həqiqətən cəfəngiyatdırsa , ən azı etiraz əlaməti ilə bunu etmək arzumu bildirim.

Əslində, malloc (və dostları) unsigned char * funksiyasını unsigned char * və əsasən void * istifadə etməyin funksiyaları ilə malloc etmək yaxşı bir təcrübədir. Əgər hər hansı bir obyektə ümumi bir göstəriciyə ehtiyac varsa, char * və ya unsigned char * istifadə edin və hər iki istiqamətə atın. Yəqin ki, memset bilən yeganə istirahət, memsetmemcpy kimi funksiyaları istifadə edir.

C ++ ilə döküm və uyğunluq məsələsində kodunuzu C və C ++ kimi tərtib edərkən yazarsanız (bu halda void * fərqli bir şey təyin etdiyinizdə geri dönüş dəyəri malloc ) void * özünüz üçün çox faydalı bir şey edə bilərsiniz: C ++ kimi tərtib edildikdə C ++ üslubuna çevrilən, lakin C kimi tərtib edildikdə C çərçivəsinə düşən döküm üçün makrolardan istifadə edə bilərsiniz:

  #ifdef __cplusplus #define strip_qual(TYPE, EXPR) (const_cast<TYPE>(EXPR)) #define convert(TYPE, EXPR) (static_cast<TYPE>(EXPR)) #define coerce(TYPE, EXPR) (reinterpret_cast<TYPE>(EXPR)) #else #define strip_qual(TYPE, EXPR) ((TYPE) (EXPR)) #define convert(TYPE, EXPR) ((TYPE) (EXPR)) #define coerce(TYPE, EXPR) ((TYPE) (EXPR)) #endif 

Bu makrolara bağlı qalarsanız, bu identifikatorlar üçün kodunuzun basit bir grep axtarışı, bütün atışlarınızın harada olduğunu göstərəcəkdir, onlardan hər hansı birinin yanlış olub olmadığını yoxlaya bilərsiniz.

Ardından, davamlı olaraq C ++ kodunu tərtib edərsəniz, müvafiq döküm istifadə edəcək. Məsələn, strip_qual istifadə yalnız const və ya volatile aradan qaldırılması üçün, lakin proqram bir növ dönüşüm meydana ki, belə bir şəkildə dəyişir, siz bir diaqnoz alacaq və istədiyiniz dönüşüm əldə etmək üçün döküm birləşməsi istifadə etmək lazımdır.

Чтобы помочь вам придерживаться этих макросов, компилятор GNU С++ (не C!) имеет красивую функцию: необязательную диагностику, которая создается для всех вхождений приведения стиля C.

 -Wold-style-cast (C++ and Objective-C++ only) Warn if an old-style (C-style) cast to a non-void type is used within a C++ program. The new-style casts (dynamic_cast, static_cast, reinterpret_cast, and const_cast) are less vulnerable to unintended effects and much easier to search for.

Если ваш C-код скомпилирован как С++, вы можете использовать этот параметр -Wold-style-cast , чтобы узнать все вхождения синтаксиса (type) , который может входить в код, и следить за этими диагностиками, заменив его соответствующим выбор из вышеупомянутых макросов (или комбинация, если необходимо).

Эта обработка конверсий является самым большим автономным техническим обоснованием для работы в "Чистом C": комбинированном диалекте C и С++, который, в свою очередь, технически оправдывает литье возвращаемого значения malloc .

11
ответ дан Kaz 30 марта '16 в 3:23 2016-03-30 03:23

Нет, вы не выполняете результат malloc() .

В общем, вы не прикладываете к или из void * .

Типичная причина, по которой это не делается, заключается в том, что отказ #include <stdlib.h> может остаться незамеченным. Это уже не проблема уже давно, так как C99 делает неявные декларации функций незаконными, поэтому, если ваш компилятор соответствует по крайней мере C99, вы получите диагностическое сообщение.

Но существует гораздо более сильная причина не вводить ненужные приведения указателей:

В C литье указателей почти всегда является ошибкой . Это происходит из-за следующего правила ( §6.5 p7 в N1570, последний черновик для C11):

Объект должен иметь сохраненное значение, доступ к которому имеет только выражение lvalue, которое имеет один из следующие типы:
- тип, совместимый с эффективным типом объекта,
- квалифицированная версия типа, совместимая с эффективным типом объекта,
- тип, который является подписанным или неподписанным типом, соответствующим эффективному типу объект,
- тип, который является подписанным или неподписанным типом, соответствующим квалифицированной версии эффективный тип объекта,
- совокупный или объединенный тип, который включает один из вышеупомянутых типов среди его членов (в том числе, рекурсивно, члена субагрегата или объединенного союза), или
- тип символа.

Это также известно как правило строгого сглаживания. Таким образом, следующий код: undefined поведение:

 long x = 5; double *p = (double *) double y = *p; 

И, иногда удивительно, следующее:

 struct foo { int x; }; struct bar { int x; int y; }; struct bar b = { 1, 2}; struct foo *p = (struct foo *) int z = p->x; 

Иногда вам делать нужно указывать указатели, но с учетом строгого правила псевдонимов вы должны быть очень осторожны с ним. Таким образом, любое появление указателя, введенного в вашем коде, - это место, где вы должны дважды проверять его достоверность . Поэтому вы никогда не пишете ненужный указатель.

DR. DR

В двух словах: потому что в C, любое появление указателя должно поднять красный флаг для кода, требующего особого внимания, вы никогда не должны писать ненужные приведения указателей.


Боковые заметки:

  • Бывают случаи, когда вам действительно нужен бросок на void * , например. если вы хотите напечатать указатель:

     int x = 5; printf("%p\n", (void *)> 

    Приведение необходимо здесь, потому что printf() является вариационной функцией, поэтому неявные преобразования не работают.

  • В С++ ситуация другая. Типы указателей заливки несколько распространены (и правильны) при работе с объектами производных классов. Поэтому имеет смысл, что в С++ преобразование в и из void * не соответствует не . С++ имеет целый набор различных вкусов кастинга.

10
ответ дан user2371524 16 авг. '17 в 15:25 2017-08-16 15:25

Кастинг предназначен только для С++, а не C. Если вы используете компилятор С++, вы лучше меняете его на компилятор C.

10
ответ дан user3949394 10 сент. '15 в 18:58 2015-09-10 18:58

Лучшее, что нужно делать при программировании на C, когда это возможно:

  • Сделайте компиляцию вашей программы с помощью компилятора C со всеми предупреждениями, включенными в -Wall , и исправьте все ошибки и предупреждения
  • Убедитесь, что нет переменных, объявленных как auto
  • Затем скомпилируйте его с помощью компилятора С++ с -Wall и -std=c++11 . Исправьте все ошибки и предупреждения.
  • Теперь скомпилируйте с помощью компилятора C еще раз. Ваша программа должна теперь компилироваться без предупреждения и содержать меньше ошибок.

Эта процедура позволяет вам использовать проверку строгих типов С++, тем самым уменьшая количество ошибок. В частности, эта процедура заставляет вас включать stdlib.h или вы получите

malloc не был объявлен в этой области

а также заставляет вас отображать результат malloc или вы получите

неверное преобразование от void* до T*

или какой бы тип вашего целевого объекта не был.

Единственные преимущества написания в C вместо С++, которые я могу найти, - это

  • C имеет четко определенный ABI
  • С++ может генерировать больше кода [исключения, RTTI, шаблоны, полиморфизм времени выполнения]

Обратите внимание на то, что второй недостаток в идеальном случае исчезает при использовании общего подмножества C вместе со статическим полиморфным признаком.

Для тех, кто считает строгие правила С++ неудобными, мы можем использовать функцию С++ 11 с выведенным типом

 auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow... 
10
ответ дан user877329 12 июня '15 в 18:23 2015-06-12 18:23

Я предпочитаю делать актеры, но не вручную. Мой любимый использует макросы g_new и g_new0 из glib. Если glib не используется, я бы добавил похожие макросы. Эти макросы уменьшают дублирование кода без ущерба для безопасности типа. Если вы ошиблись, вы получите неявный бросок между не-void указателями, что вызовет предупреждение (ошибка в С++). Если вы забудете включить заголовок, который определяет g_new и g_new0 , вы получите сообщение об ошибке. g_new и g_new0 оба принимают те же аргументы, в отличие от malloc , который принимает меньше аргументов, чем calloc . Просто добавьте 0 для получения нулевой инициализации памяти. Код может быть скомпилирован с помощью компилятора С++ без изменений.

10
ответ дан proski 29 июня '16 в 10:30 2016-06-29 10:30

Концепция указателя void заключается в том, что он может быть применен к любому типу данных, поэтому malloc возвращает void. Также вы должны знать о автоматическом приведении типов. Поэтому не обязательно указывать указатель, хотя вы должны это делать. Это помогает сохранить код чистым и помогает отлаживать

9
ответ дан iec2011007 29 июля '15 в 8:53 2015-07-29 08:53

Указатель void является общим указателем, а C поддерживает неявное преобразование из типа указателя void в другие типы, поэтому нет необходимости явно указывать его.

Однако, если вы хотите, чтобы один и тот же код работал полностью совместимым на платформе С++, который не поддерживает неявное преобразование, вам нужно сделать typecasting, поэтому все зависит от удобства использования.

5
ответ дан dhana govindarajan 18 июля '16 в 13:36 2016-07-18 13:36
  • Как и указано, он не нужен для C, но для С++.

  • Включение роли может позволить программе или функции C скомпилироваться как С++.

  • В C нет необходимости, поскольку void * автоматически и безопасно продвигается к любому другому типу указателя.

  • Но если вы затем нажмете, он может скрыть ошибку, если вы забыли включить stdlib.h . Это может привести к сбоям (или, что еще хуже, не вызвать сбой до конца позже в какой-то совершенно другой части кода).

    Потому что stdlib.h содержит прототип для malloc. в отсутствие прототипа для malloc, стандарт требует, чтобы C компилятор предполагает, что malloc возвращает int. Если нет броска, предупреждение выдается, когда этому целому числу присваивается указатель; однако, с литой, это предупреждение не создается, скрывая ошибку.

5
ответ дан Mohit 08 нояб. '16 в 13:09 2016-11-08 13:09

Здесь актерский состав не нужен вообще. Под языком C вы можете неявно конвертировать пустой указатель в любой другой указатель.

4
ответ дан Ashwini Mohan 21 дек. '18 в 8:33 2018-12-21 08:33

Кастинг malloc не нужен в C, но обязателен в C++.

Кастинг не нужен в C из-за:

  • void * автоматически и безопасно продвигается к любому другому типу указателя в случае C.
  • Он может скрыть ошибку, если вы забыли включить <stdlib.h> . Это может привести к сбоям.
  • Если указатели и целые числа имеют разный размер, тогда вы скрываете предупреждение путем кастинга и можете потерять бит вашего возвращенного адреса.
  • Если тип указателя изменяется при его объявлении, также может потребоваться изменить все строки, в которых malloc вызывается и выполняется.

С другой стороны, кастинг может увеличить переносимость вашей программы. yəni, он позволяет программе или функции C компилироваться как C++.

2
ответ дан Aashish 03 окт. '17 в 16:13 2017-10-03 16:13

Пожалуйста, сделайте себе одолжение и, что более важно, пользу для следующего человека, который будет поддерживать ваш код, и предоставить как можно больше информации о типе данных программных переменных.

Таким образом, cast возвращаемый указатель из malloc . В следующем коде компилятор может быть уверен, что сите фактически присваивается точка целому числу.

  int *sieve = (int *) malloc(sizeof(int) * length); 

Это уменьшает вероятность возникновения человеческой ошибки при изменении типа данных для сита.

Мне было бы интересно узнать, есть ли какие-либо "чистые" компиляторы C, которые бы помешали этому утверждению как ошибочные. Если да, сообщите мне, чтобы я мог избежать их, поскольку их отсутствие проверки типов увеличит общий расход на обслуживание программного обеспечения.

-3
ответ дан JackCColeman 03 авг. '13 в 22:53 2013-08-03 22:53

Другие вопросы по меткам или Задайте вопрос