سؤال

في هذا السؤال, أحدهم اقترح في التعليق التي يجب أن لا يلقي نتيجة malloc, أي

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

بدلا من:

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

لماذا تكون هذه القضية ؟

هل كانت مفيدة؟

المحلول

لا;لك لا يلقي لذلك:

  • هو لا لزوم لها ، void * تلقائيا وأمان ترقيته إلى أي نوع المؤشر في هذه الحالة.
  • وتضيف فوضى إلى رمز ، يلقي ليست من السهل جدا قراءة (خاصة إذا كان نوع مؤشر طويلة).
  • يجعل تكرار نفسك ، الذي هو عادة سيئة.
  • فإنه يمكن إخفاء خطأ إذا كنت قد نسيت أن تشمل <stdlib.h>.هذا يمكن أن يسبب تعطل (أو ما هو أسوأ ، لا تسبب حادث تحطم حتى الطريق في وقت لاحق في بعض مختلف تماما جزءا من القانون).النظر في ما يحدث إن المؤشرات هي الأعداد الصحيحة بشكل مختلف الحجم ؛ ثم أنت تخفي تحذير قبل الصب و قد تفقد اجزاء من عاد العنوان.ملاحظة:كما من C11 الضمني وظائف ولت من ج ، و هذه النقطة لم يعد مناسبا لأن ليس هناك التلقائي افتراض أن وظائف غير معلنة عودة int.

توضيح لاحظ أني قلت "لا يلقي" وليس "أنت لا تحتاج أن يلقي".في رأيي, هو عدم إدراج المدلى بها ، حتى إذا كنت حصلت على ذلك الحق.ببساطة لا يوجد هناك فوائد القيام بذلك ، ولكن مجموعة من المخاطر المحتملة ، بما في ذلك يلقي يدل على أنك لا تعرف عن المخاطر.

نلاحظ أيضا, كما المعلقين يشيرون إلى أن ما ورد أعلاه يتحدث عن مستقيم C وليس C++.أنا نعتقد اعتقادا راسخا جدا في C و C++ لغات مستقلة.

لإضافة مزيد من التعليمات البرمجية داع يكرر نوع المعلومات (int) والتي يمكن أن تتسبب في حدوث أخطاء.فمن الأفضل إلغاء مرجعية مؤشر يستخدم لتخزين قيمة الإرجاع إلى "قفل" اثنين معا:

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

هذا أيضا يتحرك length إلى الجبهة من أجل زيادة وضوح, و قطرات زائدة قوسين مع sizeof;أنها مطلوبة فقط عندما الحجة هي اسم نوع.يبدو أن العديد من الناس لا يعرفون (أو تجاهل) هذا الذي يجعل التعليمات البرمجية الخاصة بهم أكثر مطول.تذكر: sizeof ليست وظيفة!:)


بينما تتحرك length إلى الأمام قد زيادة الرؤية في بعض الحالات النادرة ، ينبغي أيضا الانتباه إلى أنه في الحالة العامة ، ينبغي أن يكون أفضل لكتابة التعبير:

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

منذ الحفاظ على sizeof أولا ، في هذه الحالة ، يضمن الضرب به على الأقل size_t الرياضيات.

قارن: malloc(sizeof *sieve * length * width) مقابل malloc(length * width * sizeof *sieve) الثاني قد تجاوز length * width عندما width و length هي أصغر أنواع من size_t.

نصائح أخرى

في C, أنت لا تحتاج أن يلقي قيمة الإرجاع malloc.المؤشر إلى الفراغ عاد قبل malloc هو التلقائى تحويلها إلى النوع الصحيح.ومع ذلك ، إذا كنت تريد الخاص بك رمز تجميع مع برنامج التحويل البرمجي C++, يلقي هو مطلوب.بديلا المفضل بين المجتمع هو استخدام ما يلي:

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

والتي بالإضافة إلى ذلك يخلصك من الحاجة إلى القلق حول تغيير الجانب الأيمن من التعبير إذا سبق لك تغيير نوع sieve.

يلقي بظلال سيئة ، أشار.خصيصا مؤشر يلقي.

لك هل يلقي لأن:

  • يجعل التعليمات البرمجية الخاصة بك أكثر المحمولة بين C و C++ ، كما تبين التجربة ، عدد كبير من المبرمجين يدعون أنهم الكتابة في ج عندما كانوا حقا الكتابة في C++ (C أو زائد المحلية مترجم ملحقات).
  • الفشل في القيام بذلك يمكن إخفاء خطأ:ملاحظة جميع ذلك أمثلة من مربكا عند الكتابة type * مقابل type **.
  • فكرة أن يبقى لك من يلاحظ فشلت #include مناسبة رأس الملف يفتقد الغابة للأشجار.هو نفس قوله "لا تقلق بشأن حقيقة أنك لم يطلب من المترجم أن يشكو من عدم رؤية النماذج-أن المزعجة stdlib.h هو أهم شيء أن نتذكر!"
  • انها قوات غير إضافية المعرفية عبر الاختيار.فإنه يضع (المزعومة) النوع المطلوب بجانب الحساب تفعله الخام حجم هذا المتغير.أراهن أنك يمكن أن تفعل ذلك الدراسة التي تظهر أن malloc() البق يتم القبض أسرع بكثير عندما يكون هناك المدلى بها.كما هو الحال مع تأكيدات والشروح التي تكشف عن نوايا تقليل الأخطاء.
  • تكرار نفسك في طريق هذا الجهاز يمكن أن تحقق كثير من الأحيان رائعة فكرة.في الواقع, هذا ما تأكيد و هذا الاستخدام من الزهر هو تأكيد.التأكيدات لا تزال معظم العامة تقنية لدينا للحصول على التعليمات البرمجية الصحيحة ، تورينج منذ جاء مع فكرة منذ سنوات عديدة.

وغيرها من ذكر ، فإنه ليست هناك حاجة ج ، ولكن ل C++.إذا كنت تعتقد أنك ذاهب إلى تجميع التعليمات البرمجية C مع برنامج التحويل البرمجي C++ ، والتي الأسباب على الإطلاق ، يمكنك استخدام ماكرو بدلا من ذلك ، مثل:

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

وبهذه الطريقة يمكنك لا يزال يكتب في صغير جدا الطريقة:

int *sieve = NEW(int, 1);

وأنه سيتم ترجمة ل C و C++.

من ويكيبيديا:

مزايا الصب

  • بما في ذلك يلقي قد يسمح برنامج C أو وظيفة تجميع مثل C++.

  • يلقي يسمح ما قبل 1989 إصدارات malloc أن الأصل عاد شار *.

  • الصب يمكن أن تساعد المطور تحديد أوجه الاختلاف في نوع التحجيم أن الوجهة مؤشر تغيير نوع ولا سيما إذا كان المؤشر غير المعلنة حتى الآن من malloc() call (على الرغم من أن الحديث المجمعين ثابتة تحليل يمكن تحذير على مثل هذا السلوك دون اشتراط الزهر).

عيوب الصب

  • تحت ANSI C القياسية, المدلى بها هي زائدة عن الحاجة.

  • إضافة يلقي قد تخفي عدم إدراج رأس stdlib.ح, في وهو نموذج malloc وجدت.في غياب نموذج malloc ، يتطلب المعيار أن المحول البرمجي C نفترض malloc يعود الباحث.إذا كان هناك أي الزهر ، التحذير أصدر عند هذا صحيح يتم تعيين المؤشر ، ومع ذلك ، يلقي هذا التحذير ليس المنتجة ، إخفاء الشوائب.على بعض أبنية و نماذج البيانات (مثل LP64 على أنظمة 64 بت ، حيث طويلة و مؤشرات 64 بت و الباحث هو 32 بت) ، هذا الخطأ فعلا النتيجة في غير معرف السلوك ، كما أعلن ضمنا malloc بإرجاع قيمة 32 بت بينما في الواقع وظيفة محددة إرجاع قيمة 64-بت.اعتمادا على الاتفاقيات الدعوة و الذاكرة تخطيط ، وهذا قد يؤدي إلى تحطم المكدس.هذه المسألة هي أقل احتمالا أن تذهب دون أن يلاحظها أحد في الحديث المجمعين ، كما أنها تنتج بشكل موحد تحذيرات غير معلنة وظيفة وقد استخدمت لذلك سوف تحذير لا تزال تظهر.على سبيل المثال في دول مجلس التعاون الخليجي السلوك الافتراضي هو أن تظهر محذرا من أن يقرأ "يتعارض ضمنيا إعلان المدمج في وظيفة" بغض النظر عما إذا كان يلقي موجودا أم لا.

  • إذا كان نوع من المؤشر هو تغير في إعلان واحد قد كما تحتاج إلى تغيير جميع الخطوط حيث malloc يسمى الزهر.

على الرغم من أن malloc دون الصب هو الأسلوب المفضل والأكثر خبرة المبرمجين اختيار, يجب عليك استخدام أيهما تحب أن على بينة من القضايا.

أنا.هـ:إذا كنت تحتاج إلى ترجمة برنامج C C++(على الرغم من أن تلك هي منفصلة اللغة) يجب عليك استخدام malloc مع الصب.

في C يمكنك تحويل ضمنيا الفراغ مؤشر إلى أي نوع آخر من مؤشر حتى يلقي ليست ضرورية.باستخدام واحدة قد توحي للمراقب عارضة أن هناك سبب واحد هو الحاجة التي قد تكون مضللة.

لا يلقي نتيجة malloc ، لأن ذلك يضيف لا طائل من فوضى إلى التعليمات البرمجية الخاصة بك.

السبب الأكثر شيوعا لماذا الناس يلقي نتيجة malloc لأنهم غير متأكد حول كيفية لغة C يعمل.هذا هو علامة تحذير:إذا كنت لا تعرف كيف لغة معينة الآلية ، ثم لا اتخاذ تخمين.البحث عنه أو تسأل على تجاوز سعة مكدس.

بعض التعليقات:

  • الفراغ مؤشر يمكن تحويلها إلى/من أي نوع المؤشر دون صريح الزهر (C11 6.3.2.3 و 6.5.16.1).

  • C++ لكن لا تسمح ضمني بين الزهر void* و آخر نوع مؤشر.حتى في C++, المدلى بها كانت صحيحة.ولكن إذا كان البرنامج في C++, يجب عليك استخدام new وليس malloc().و يجب أن لا ترجمة التعليمات البرمجية C باستخدام برنامج التحويل البرمجي C++.

    إذا كنت بحاجة إلى دعم كل من C و C++ مع نفس شفرة المصدر ، استخدام برنامج التحويل البرمجي التبديل إلى علامة الخلافات.لا تحاول أن أشبع كل لغة المعايير مع نفس القانون ، لأنها ليست متوافقة.

  • إذا كان التحويل البرمجي C لا يمكن العثور على وظيفة لأنك نسيت أن تشمل رأس ، سوف تحصل على مترجم/رابط خطأ حول ذلك.حتى إذا كنت قد نسيت أن تشمل <stdlib.h> هذا ليس بالأمر الكبير, أنت لن تكون قادرة على بناء البرنامج الخاص بك.

  • على القديمة المجمعين التي تتبع النسخة القياسية التي هي أكثر من 25 عاما ، متناسين أن تشمل <stdlib.h> من شأنه أن يؤدي إلى سلوك خطير.لأن في ذلك القديمة القياسية, وظائف بدون مرئية النموذج ضمنا تحويل نوع الإرجاع إلى int.صب النتيجة من malloc صراحة ثم إخفاء هذا الخلل.

    ولكن هذا هو حقا غير هذه المسألة.كنت لا تستخدم 25 عاما الكمبيوتر فلماذا استخدام 25 عاما ومترجم ؟

في ج تحصل على التحويل الضمني من void* أي (البيانات) مؤشر.

صب القيمة التي تم إرجاعها من قبل malloc() ليس من الضروري الآن ولكن أود أن أضيف نقطة واحدة يبدو أن لا أحد قد أشار إلى:

في الأيام القديمة ، ANSI C يوفر void * كما نوع عام من المؤشرات ، char * هو نوع هذا الاستخدام.في هذه الحالة يمكن أن يلقي اغلاق مترجم التحذيرات.

المرجع: ج التعليمات

فإنه ليس إلزاميا أن يلقي نتائج malloc, لأنه يعود void* ، void* يمكن أن يشير إلى أي نوع بيانات.

فقط إضافة تجربتي, دراسة هندسة الكمبيوتر أرى أن اثنين أو ثلاثة أساتذة التي رأيت الكتابة في ج دائما يلقي malloc ، ومع ذلك واحدة سألت (مع هائلة السيرة الذاتية وفهم ج) أخبرني أنه لا لزوم لها على الاطلاق ولكن تستخدم فقط أن تكون محددة تماما ، والحصول على الطلاب في عقلية من كونها محددة تماما.أساسا صب لن يغير شيئا في كيف يعمل يفعل بالضبط ما يقول ، يخصص الذاكرة و الصب لا تأثير ذلك ، يمكنك الحصول على نفس الذاكرة ، وحتى لو كنت المدلى بها إلى شيء آخر عن طريق الخطأ (و بطريقة ما التهرب من أخطاء برنامج التحويل البرمجي) C الوصول إليها بنفس الطريقة.

تحرير: صب له نقطة معينة.عند استخدام مجموعة الرموز الشفرة التي تم إنشاؤها يجب أن تعرف كيف العديد من ذاكرة الأماكن التي يجب أن تقدم إلى الوصول إلى بداية العنصر التالي ، ويتحقق هذا من خلال الصب.بهذه الطريقة أنت تعرف أن ضعف تذهب 8 بايت قبل حين الباحث تذهب 4, وهلم جرا.وبالتالي فإنه ليس له أي تأثير إذا كنت تستخدم مؤشر التدوين في تدوين مجموعة يصبح من الضروري.

هذا هو ما GNU C مرجع مكتبة دليل يقول:

يمكنك تخزين نتيجة malloc إلى أي مؤشر متغير دون يلقي لأن ISO C تلقائيا بتحويل نوع void * إلى آخر نوع المؤشر عند الضرورة.ولكن يلقي ضروري في سياقات وغيرها من عوامل التعيين أو إذا كنت قد ترغب في التعليمات البرمجية لتشغيل في التقليدية C.

بل ISO C11 القياسية (p347) يقول في ذلك:

المؤشر عاد إذا كان تخصيص ينجح هو مناسب الانحياز حتى أنه قد يتم تعيين مؤشر إلى أي نوع من الكائن مع الأساسية محاذاة شرط ثم استخدامها للوصول إلى مثل هذا كائن أو مجموعة من هذه الكائنات في المساحة المخصصة (حتى مساحة صراحة deallocated)

الفراغ المؤشر العام مؤشر C يدعم التحويل الضمني من فراغ نوع مؤشر إلى أنواع أخرى ، لذلك ليس هناك حاجة صراحة بتلبيس ذلك.

ومع ذلك ، إذا كنت تريد نفس رمز العمل متوافقة تماما على C++ منصة, التي لا تدعم التحويل الضمني ، تحتاج إلى القيام بتلبيس, لذلك كل هذا يتوقف على قابلية الاستخدام.

عاد النوع هو باطل* ، والتي يمكن أن يلقي إلى النوع المطلوب من بيانات مؤشر من أجل أن تكون dereferenceable.

في لغة C, الفراغ مؤشر يمكن أن تسند إلى أي مؤشر ، وهذا هو السبب يجب عدم استخدام نوع الزهر.إذا كنت تريد نوع "آمنة" تخصيص يمكنني أن أوصي الماكرو التالي وظائف, والتي دائما ما تستخدم في ج المشاريع:

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

هذه في مكان يمكنك أن تقول ببساطة

NEW_ARRAY(sieve, length);

غير صفائف ديناميكية الثالث يجب أن يكون وظيفة الماكرو

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

مما يجعل مجموعة حلقات أكثر أمانا وأكثر ملاءمة:

int i, a[100];

for (i = 0; i < LEN(a); i++) {
   ...
}

ذلك يعتمد على لغة البرمجة و مترجم.إذا كنت تستخدم malloc في ج ليس هناك حاجة إلى نوع من الزهر ، فإنه سيتم تلقائيا نوع المدلى بها ، ومع ذلك إذا كان لديك باستخدام C++ ثم يجب أن نوع يلقي لأن malloc سيعود void* نوع.

اعتاد الناس على دول مجلس التعاون الخليجي و رنة هي مدلل.ليس هذا شيء جيد هناك.

لقد كنت جميلة بالرعب على مر السنين من قبل بشكل مذهل الذين تتراوح أعمارهم بين المجمعين كنت المطلوبة للاستخدام.في كثير من الأحيان الشركات والمديرين اعتماد فائقة النهج المحافظ إلى تغيير المجمعين و لا حتى اختبار إذا جديد مترجم ( مع أفضل معايير رمز الأمثل ) سوف تعمل في النظام الخاص بهم.الواقع العملي للعمل المطورين هو أنه عندما كنت الترميز تحتاج إلى تغطية القواعد الخاصة بك و, للأسف, صب mallocs هو عادة جيدة إذا كنت لا تستطيع السيطرة على ما المترجم قد يتم تطبيق التعليمات البرمجية الخاصة بك.

أود أن أقترح أيضا أن العديد من المنظمات تطبيق الترميز القياسية الخاصة بها و التي أن يجب أن يكون الأسلوب اتبع الناس إذا لم يتم تعريف.في غياب التوجيه الصريح أنا أميل إلى أن تذهب على الأرجح إلى تجميع كل مكان بدلا من الخنوع الالتزام القياسية.

بحجة أنه ليس من الضروري في ظل المعايير الحالية غير صالحة تماما.ولكن هذه الحجة يغفل الجوانب العملية في العالم الحقيقي.نحن لا رمز في عالم قضت حصريا القياسية من اليوم ، ولكن قبل العملية ما أحب أن أسميه "الإدارة المحلية الواقع الميداني".وهذا عازمة الملتوية أكثر من مساحة أي وقت مضى كان.:-)

YMMV.

أنا أميل إلى التفكير في صب malloc بأنها عملية دفاعية.ليست جميلة ، ليست مثالية, ولكن عموما آمنة.( بصراحة, إذا كنت لم شمل stdlib.ساعة ثم قمت طريقة مشاكل أكثر من صب malloc !).

أنا وضعت في المدلى بها ببساطة لإظهار استيائها من القبيح ثقب في نوع النظام الذي يسمح رمز مثل المقتطف التالي لتجميع دون تشخيص ، حتى وإن كان لا يلقي تستخدم لتحقيق سيئة التحويل:

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

أتمنى أن لم تكن موجودة (و لا في C++) و لذلك أنا المدلى بها.لأنها تمثل ذوقي و البرمجة السياسة.أنا لا يلقي المؤشر ، ولكن على نحو فعال ، في صناديق الاقتراع ، يلقي بها الشياطين من الغباء.إذا كنت لا يمكن أن فعلا يلقي بها الغباء, فعلى الأقل اسمحوا لي أن أعرب عن رغبته في القيام بذلك مع لفتة من الاحتجاج.

في الواقع ممارسة جيدة هو التفاف malloc (والأصدقاء) مع وظائف عودة unsigned char *, و أساسا لا تستخدم void * في التعليمات البرمجية الخاصة بك.إذا كنت في حاجة الى عام المؤشر إلى أي كائن استخدام char * أو unsigned char *, و قد يلقي في كلا الاتجاهين.واحد الاسترخاء التي يمكن أن تكون منغمس ، ربما ، هو استخدام وظائف مثل memset و memcpy دون أن يلقي.

على الموضوع الصب و C++ التوافق ، إذا كان يمكنك كتابة التعليمات البرمجية الخاصة بك بحيث يجمع على حد سواء C و C++ (في هذه الحالة يجب أن يلقي قيمة الإرجاع malloc عند تعيين هذا إلى شيء آخر غير void *), يمكنك أن تفعل مفيدة جدا شيء لنفسك:يمكنك استخدام وحدات الماكرو الصب والتي تترجم إلى C++ نمط يلقي عند ترجمة مثل C++, ولكن تقلل إلى ج الزهر عند ترجمة مثل C:

/* In a header somewhere */
#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

إذا كنت الانضمام إلى وحدات الماكرو هذه ، ثم بسيط grep البحث الخاص بك رمز قاعدة هذه المعرفات سوف تظهر لك حيث كل ما تبذلونه من يلقي ، حتى تتمكن من مراجعة ما إذا كان أي منهم غير صحيحة.

ثم المضي قدما إذا كنت بانتظام ترجمة التعليمات البرمجية مع C++, فإنه سيتم فرض استخدام مناسب المدلى بها.على سبيل المثال, إذا كنت تستخدم strip_qual فقط لإزالة const أو volatile, لكن التغييرات البرنامج في مثل هذه الطريقة أن نوع التحويل تشارك الآن, سوف تحصل على التشخيص ، وسوف تضطر إلى استخدام مزيج من يلقي للحصول على التحويل المطلوب.

لمساعدتك على الانضمام إلى وحدات الماكرو هذه ، GNU 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 يجمع مثل C++, يمكنك استخدام هذا -Wold-style-cast الخيار لمعرفة كافة تواجدات (type) صب الجملة التي قد زحف إلى رمز ، ومتابعة هذه التشخيص عن طريق استبدال ذلك مع الاختيار المناسب من بين فوق وحدات الماكرو (أو مزيج ، إذا لزم الأمر).

هذا العلاج من التحويلات هو أكبر مستقل مبرر تقني يعمل في "نظيفة ج":الجمع بين C و C++ اللهجة ، والذي بدوره تقنيا يبرر صب قيمة الإرجاع malloc.

أن أفضل شيء نفعله عندما البرمجة في C كلما كان ذلك ممكنا:

  1. جعل الخاص بك برنامج ترجمة عن طريق التحويل البرمجي C مع كل التحذيرات تشغيل -Wall و إصلاح كافة الأخطاء والتحذيرات
  2. تأكد من أن هناك متغيرات أعلن auto
  3. ثم ترجمة ذلك باستخدام برنامج التحويل البرمجي C++ مع -Wall و -std=c++11.إصلاح كافة الأخطاء والتحذيرات.
  4. الآن تجميع باستخدام برنامج التحويل البرمجي C مرة أخرى.البرنامج الآن تجميع دون أي تحذير تحتوي على عدد أقل من الأخطاء.

هذا الإجراء يتيح لك الاستفادة من C++ صارمة نوع التحقق ، وبالتالي تقليل عدد الأخطاء.وخاصة أن هذا الإجراء يفرض عليك أن تشمل stdlib.hأو سوف تحصل على

malloc لم تعلن ضمن هذا النطاق

و يفرض عليك أيضا أن يلقي نتيجة malloc أو سوف تحصل على

صالح التحويل من void* إلى T*

أو ما من أي وقت مضى الهدف الخاص بك نوع هو.

فوائد الوحيد من الكتابة في ج بدلا من C++ يمكنني العثور على

  1. ج كما هو محدد أبي
  2. C++ قد تولد المزيد من التعليمات البرمجية [الاستثناءات ، RTTI ، قوالب ، وقت التشغيل تعدد الأشكال]

لاحظ أن الثاني سلبيات يجب في الحالة المثالية تختفي عند استخدام فرعية مشتركة C جنبا إلى جنب مع ثابت متعددة الأشكال الميزة.

لمن يجد C++ قواعد صارمة غير مريح ، يمكننا استخدام C++11 ميزة مع الاستدلال على نوع

auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...

لا, أنت لا يلقي نتيجة malloc().

في العام ، لا الزهر أو من void *.

نموذجي سبب لعدم القيام بذلك هو أن عدم #include <stdlib.h> يمكن أن تذهب دون أن يلاحظها أحد.هذه ليست مشكلة بعد الآن لفترة طويلة الآن كما جعلت C99 الدالة الضمنية الإعلانات غير ذلك إذا كان المترجم الخاص بك يتوافق مع على الأقل C99, سوف تحصل على رسالة تشخيص.

ولكن هناك أقوى سبب عدم إدخال غير الضرورية مؤشر يلقي:

في C ، مؤشر الزهر هو دائما تقريبا خطأ.هذا بسبب القاعدة التالية (§6.5 p7 في N1570, أحدث مشروع C11):

كائن يكون القيمة المخزنة الوصول إليها إلا عن طريق lvalue التعبير التي لديها واحد من الأنواع التالية:
— نوع متوافق مع نوع فعالة من وجوه ،
— مؤهل نسخة من نوع متوافق مع نوع فعالة من وجوه ،
— هو نوع من موقعة أو غير موقعة نوع المقابلة الفعالة نوع من الكائن ،
— هو نوع من موقعة أو غير موقعة نوع المقابلة المؤهلة نسخة من فعالة نوع الكائن ،
— مجمعة أو الاتحاد النوع الذي يشمل الذكر بين أنواع أعضاء (بما في ذلك ، بشكل متكرر ، عضو subaggregate أو الواردة الاتحاد) ، أو
— نوع الحرف.

هذا هو المعروف أيضا باسم صارمة التعرج القاعدة.لذا التعليمة البرمجية التالية السلوك غير معرف:

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

وفي بعض الأحيان من المستغرب ، وفيما يلي أيضا:

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

في بعض الأحيان ، هل تحتاج إلى المدلى بها من مؤشرات ، ولكن نظرا صارمة التعرج القاعدة, عليك أن تكون حذرا جدا مع ذلك.لذا وقوع أي مؤشر يلقي في التعليمات البرمجية الخاصة بك هو المكان الذي يجب أن انقر نقرا مزدوجا التحقق من صحة.ولذلك لم أكتب غير ضرورية مؤشر المدلى بها.

tl;dr

باختصار:لأن في C ، أي حدوث مؤشر الزهر أن رفع العلم الاحمر رمز تتطلب عناية خاصة, يجب أن لا تكتب لا لزوم لها مؤشر يلقي.


الملاحظات الجانبية:

  • هناك حالات حيث كنت في الواقع تحتاج المدلى بها إلى void *, مثلاإذا كنت ترغب في طباعة المؤشر:

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

    الزهر هو ضروري هنا ، لأن printf() هو variadic وظيفة ، الضمني لذلك التحويلات لا تعمل.

  • في C++ ، فإن الوضع يختلف.صب مؤشر أنواع أمر شائع إلى حد ما (الصحيح) عند التعامل مع الكائنات من الفئات المشتقة.ولذلك فمن المنطقي أن في C++ ، التحويل من و إلى void * هو لا ضمني.C++ يحتوي على مجموعة كاملة من نكهات مختلفة من الصب.

أنا أفضل أن تفعل المدلى بها ، ولكن ليس يدويا.بلدي المفضل هو استخدام g_new و g_new0 وحدات الماكرو من سطحي.إذا سطحي ، وأود أن أضيف مماثلة وحدات الماكرو.هذه وحدات الماكرو تقليل رمز الازدواج دون المساس نوع الأمان.إذا كنت تحصل على نوع من الخطأ, سوف تحصل ضمني يلقي بين غير الفراغ المؤشرات التي من شأنها أن تسبب تحذير (خطأ في C++).إذا كنت تنسى أن تشمل رأس يحدد g_new و g_new0, ستحصل على خطأ. g_new و g_new0 سواء أخذ نفس الحجج ، على عكس malloc أن يأخذ أقل من الحجج calloc.فقط إضافة 0 للحصول على صفر-تهيئة الذاكرة.رمز يمكن جمعها مع C++ compiler دون تغييرات.

الصب هو فقط لل C++ لا C. في حالة كنت تستخدم C++ compiler من الأفضل تغييره إلى برنامج التحويل البرمجي C.

المفهوم الكامن وراء الفراغ المؤشر هو أنه يمكن أن يكون مسبوك إلى أي نوع بيانات هذا هو السبب malloc عوائد الفراغ.أيضا يجب أن تكون على علم التلقائي بتلبيس.لذلك فإنه ليس إلزاميا أن يلقي المؤشر على الرغم من أنك يجب أن تفعل ذلك.كما أنه يساعد في الحفاظ على رمز نظيفة و يساعد على التصحيح

  1. وغيرها من ذكر ، فإنه ليست هناك حاجة ج ، ولكن ل C++.

  2. بما في ذلك يلقي قد يسمح برنامج C أو وظيفة تجميع مثل C++.

  3. في C هو لا لزوم لها ، كما باطلة * تلقائيا وأمان ترقيته إلى أي نوع مؤشر.

  4. ولكن إذا كنت الزهر ثم ، فإنه يمكن إخفاء خطأ إذا كنت قد نسيت أن تشمل stdlib.ح.هذا يمكن أن يسبب تعطل (أو ما هو أسوأ, لا يسبب تحطم حتى الطريقة في وقت لاحق في بعض مختلف تماما جزءا من القانون).

    لأن stdlib.ح يحتوي النموذج على malloc وجدت.في غياب نموذج malloc ، يتطلب المعيار أن ج مترجم يفترض malloc يعود الباحث.إذا كان هناك أي المدلى بها ، يتم إصدار تحذير عند هذا صحيح يتم تعيين المؤشر ، ومع ذلك, مع المدلى بها ، هذا التحذير لا تنتج ، إخفاء الشوائب.

الفراغ المؤشر العام مؤشر C يدعم التحويل الضمني من فراغ نوع مؤشر إلى أنواع أخرى ، لذلك ليس هناك حاجة صراحة بتلبيس ذلك.

ومع ذلك ، إذا كنت تريد نفس رمز العمل متوافقة تماما على C++ منصة, التي لا تدعم التحويل الضمني ، تحتاج إلى القيام بتلبيس, لذلك كل هذا يتوقف على قابلية الاستخدام.

صب malloc لا لزوم لها في C ولكن إلزامية في C++.

الصب هو لا لزوم لها في ج بسبب:

  • void * تلقائيا وأمان ترقيته إلى أي نوع المؤشر في حالة C.
  • فإنه يمكن إخفاء خطأ إذا كنت قد نسيت أن تشمل <stdlib.h>.هذا يمكن أن يسبب تعطل.
  • إن مؤشرات الصحيحه هي الحجم بشكل مختلف ، ثم تخفيه تحذير قبل الصب و قد تفقد اجزاء من عاد العنوان.
  • إذا كان نوع من المؤشر هو تغير في إعلان واحد قد تحتاج أيضا إلى تغيير جميع الخطوط حيث malloc ويسمى المدلى بها.

من ناحية أخرى, صب قد تزيد قابلية البرنامج الخاص بك.أنا.ه ، فإنه يسمح برنامج C أو وظيفة تجميع مثل C++.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top