هل تستخدم NULL أو 0 (صفر) للمؤشرات في C++؟

StackOverflow https://stackoverflow.com/questions/176989

  •  05-07-2019
  •  | 
  •  

سؤال

في الأيام الأولى لـ C++ عندما تم تثبيته فوق C، لم يكن بإمكانك استخدام NULL كما تم تعريفه على أنه (void*)0.لا يمكنك تعيين NULL لأي مؤشر آخر غير void*, ، مما جعلها عديمة الفائدة نوعًا ما.في تلك الأيام، كان من المقبول أنك استخدمته 0 (صفر) للمؤشرات الفارغة.

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

if (p && !q)
  do_something();

فإن استخدام الصفر يكون أكثر منطقية (كما لو كنت تستخدم NULL, ، لا يمكنك استخدام منطقيا p && !q - تحتاج إلى المقارنة بشكل صريح NULL, ، إلا إذا افترضت NULL هو صفر، وفي هذه الحالة لماذا الاستخدام NULL).

هل هناك أي سبب موضوعي لتفضيل الصفر على NULL (أو العكس)، أم أن كل ذلك مجرد تفضيل شخصي؟

يحرر:يجب أن أضيف (وأقصد أن أقول في الأصل) أنه مع RAII والاستثناءات، نادرًا ما أستخدم مؤشرات صفر/NULL، لكن في بعض الأحيان لا تزال بحاجة إليها.

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

المحلول

وهنا تأخذ Stroustrup على هذا: C ++ أسلوب وتقنية التعليمات

<اقتباس فقرة>   

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

     

إذا كان لديك لتسمية مؤشر فارغة، الذي يطلق عليه nullptr. هذا ما يطلق عليه في C ++ (11). ثم، سيكون nullptr على الكلمة.

وقال ذلك، لا عرق الاشياء الصغيرة.

نصائح أخرى

هناك بعض الحجج (أحدها حديثة نسبيًا) والتي أعتقد أنها تتعارض مع موقف بيارن في هذا الشأن.

  1. توثيق النية

استخدام NULL يسمح بالبحث عن استخدامه ويسلط الضوء أيضًا على المطور مطلوب لاستخدام أ NULL المؤشر، بغض النظر عما إذا كان يتم تفسيره بواسطة المترجم على أنه NULL أم لا.

  1. التحميل الزائد للمؤشر و"int" نادر نسبيًا

المثال الذي يقتبسه الجميع هو:

void foo(int*);
void foo (int);

void bar() {
  foo (NULL);  // Calls 'foo(int)'
}

ومع ذلك، على الأقل في رأيي، المشكلة في ما سبق ليست في أننا نستخدم NULL لثابت المؤشر الفارغ، بل في أن لدينا كميات زائدة من 'foo' والتي تأخذ أنواعًا مختلفة جدًا من الوسائط.يجب أن تكون المعلمة int أيضًا، كأي نوع آخر سيؤدي إلى استدعاء غامض وبالتالي إنشاء تحذير مفيد للمترجم.

  1. أدوات التحليل يمكن أن تساعد اليوم!

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

  1. سي++ 11 سيكون لها جديد std::nullptr_t يكتب.

هذه هي الحجة الأحدث إلى الجدول.مشكلة 0 و NULL تتم معالجتها بشكل نشط لـ C++ 0x، ويمكنك ضمان ذلك لكل تطبيق يوفره NULL, ، أول شيء سيفعلونه هو:

#define NULL  nullptr

بالنسبة لأولئك الذين يستخدمون NULL بدلا من 0, ، سيكون التغيير عبارة عن تحسين في أمان الكتابة بجهد قليل أو بدون جهد - إذا كان هناك أي شيء، فقد يؤدي أيضًا إلى اكتشاف بعض الأخطاء في المكان الذي استخدموا فيه NULL ل 0.لأي شخص يستخدم 0 اليوم....erm...حسنًا، نأمل أن يكون لديهم معرفة جيدة بالتعبيرات العادية...

استخدم NULL. يظهر NULL القصد الخاص. أنه من 0 هو تفصيل تطبيق هذا يجب أن لا يهم.

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

في مشاريع جديدة، أضع هذا في رأس المشروع:

static const int nullptr = 0;

والآن، عندما C ++ 0X المجمعين متوافقة مع وصولها، كل ما عليك القيام به هو إزالة هذا الخط. وهناك فائدة لطيفة من ذلك هو أن يعترف البصرية ستوديو بالفعل nullptr ككلمة رئيسية، ويسلط الضوء بشكل مناسب.

أستخدم دائمًا:

  • NULL للمؤشرات
  • '\0' للحرف
  • 0.0 للعوامات والزوجي

حيث 0 سيكون بخير.إنها مسألة إشارة إلى النية.ومع ذلك، أنا لست شرجيًا حيال ذلك.

    cerr << sizeof(0) << endl;
    cerr << sizeof(NULL) << endl;
    cerr << sizeof(void*) << endl;

    ============
    On a 64-bit gcc RHEL platform you get:
    4
    8
    8
    ================

وإن المغزى من القصة. يجب عليك استخدام NULL عندما كنت تتعامل مع مؤشرات.

1) وتعلن نيتك (لا تجعل لي من خلال البحث عن كل ما تبذلونه من كود في محاولة لمعرفة ما إذا كان المتغير هو مؤشر أو أي نوع رقمي).

2) في المكالمات API معينة التي تتوقع الحجج المتغيرة، وأنها سوف تستخدم NULL-مؤشر للدلالة على نهاية القائمة حجة. في هذه الحالة، وذلك باستخدام "0" بدلا من NULL يمكن أن يسبب مشاكل. على منصة 64 بت، والدعوة va_arg تريد مؤشر 64 بت، ولكن عليك أن تكون عابرة فقط عدد صحيح 32-بت. يبدو لي مثل كنت تعتمد على الأخرى 32-بت إلى أن ركزت عليها بالنسبة لك؟ رأيت بعض المجمعين (مثل ICPC إنتل) ليست كريمة جدا - وأدى هذا في أخطاء وقت التشغيل

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

#ifndef __cplusplus
#define NULL (void*)0
#else
#define NULL 0
#endif

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

وبالإضافة إلى ذلك أنا لا تعتمد على التحويل التلقائي من الأعداد الصحيحة إلى القيم المنطقية ولكن صراحة مقارنتها.

وعلى سبيل المثال يفضل استخدام:

if (pointer_value != NULL || integer_value == 0)

وبدلا من:

if (pointer_value || !integer_value)

ويكفي أن أقول أن هذا هو تدارك كل ما في C ++ 11 حيث يمكن للمرء ببساطة استخدام nullptr بدلا من NULL، وأيضا nullptr_t هذا هو نوع من nullptr.

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

وبعد إنشاء C ++ 11، مع نوع الجديد nullptr، وقد بدأت بعض المجمعين تشكو (مع المعلمات الافتراضية) حول تمرير 0 إلى وظائف بحجج المؤشر، ل0 ليس المؤشر.

إذا تم كتابة التعليمات البرمجية باستخدام NULL، كان من الممكن إجراء بحث بسيط واستبدالها من خلال مصدر برنامج لجعله nullptr بدلا من ذلك. إذا كنت عالقة مع رمز مكتوبة باستخدام خيار 0 كمؤشر هو أكثر بكثير مملة لتحديثه.

وإذا كان لديك لكتابة رمز جديد في الوقت الراهن لمستوى C ++ 03 (ولا يمكن استخدام nullptr)، هل حقا ينبغي أن مجرد استخدام NULL. انها سوف تجعل من الاسهل بكثير بالنسبة لك لتحديث في المستقبل.

وعادة ما تستخدم 0. أنا لا أحب حدات الماكرو، وليس هناك ما يضمن أن بعض رأس طرف ثالث الذي تستخدمه لا إعادة تعريف NULL أن يكون شيئا غريبا.

هل يمكن استخدام كائن nullptr على النحو الذي اقترحه سكوت مايرز وغيرها حتى يحصل C ++ كلمة رئيسية nullptr:

const // It is a const object...
class nullptr_t 
{
public:
    template<class T>
    operator T*() const // convertible to any type of null non-member pointer...
    { return 0; }

    template<class C, class T>
    operator T C::*() const   // or any type of null member pointer...
    { return 0; }

private:
    void operator&() const;  // Can't take address of nullptr

} nullptr = {};

وجوجل "nullptr" لمزيد من المعلومات.

وعملت مرة واحدة على الجهاز حيث كان 0 عنوانا صالحا وتم تعريف NULL كقيمة ثماني الخاصة. على هذا الجهاز (0! = NULL)، لذلك رمز مثل

char *p;

...

if (p) { ... }

ولن تعمل كما هو متوقع. كنت قد لكتابة

if (p != NULL) { ... }

وعلى الرغم من أنني أعتقد معظم المجمعين تحدد NULL ك 0 في هذه الأيام ما زلت أتذكر درسا من تلك السنوات مضت:. NULL ليس بالضرورة 0

وأعتقد أن الضمانات المعيار الذي NULL == 0، لذلك يمكنك القيام به سواء. انا افضل فارغة لأنه يوثق القصد الخاص.

استخدام إما 0 أو NULL سيكون له نفس التأثير.

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

NULL، 0، 0.0، '\0'، 0x00 وكلها تترجم إلى نفس الشيء، ولكنها كيانات منطقية مختلفة في برنامجك.وينبغي استخدامها على هذا النحو.NULL هو مؤشر، 0 هو الكمية، 0x0 هي قيمة ذات بتات مثيرة للاهتمام وما إلى ذلك.لن تقوم بتعيين '\0' لمؤشر سواء تم تجميعه أم لا.

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

والغريب، وذكر أحد، بما في ذلك Stroustroup ذلك. بينما كان يتحدث كثيرا عن المعايير وجماليات لا أحد لاحظ أنه هو <م> خطورة استخدام 0 بدلا NULL، على سبيل المثال، في قائمة وسيطة متغير على العمارة حيث sizeof(int) != sizeof(void*). مثل Stroustroup، أنا أفضل 0 لأسباب جمالية، ولكن على المرء أن يكون حريصا على عدم استخدامها حيث نوعها قد تكون غامضة.

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

void foo(const Bar* pBar) { ... }

وكنت قد غالبا ما يكون قادرا على كتابة

void foo(const Bar& bar) { ... }

وبطبيعة الحال، هذا لا يعمل دائما. لكن مؤشرات فارغة يمكن استخدامها بإفراط.

وأنا مع Stroustrup على هذا :-) واحد منذ NULL ليست جزءا من اللغة، وأنا أفضل أن استخدام 0.

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

void *ptr = &something;
/* lots o' code */
ptr = NULL; // more obvious that it's a pointer and not being used

وIIRC، والمعيار لا يتطلب NULL لتكون 0، وذلك باستخدام كل ما هو معرف في هو على الارجح أفضل لالمترجم الخاص بك.

وثمة جانب آخر للجدل هو ما إذا كان يجب استخدام مقارنات منطقية (المدلى بها ضمني منطقي) أو صراحة تحقق ضد NULL، ولكن هذا الأمر الى انخفاض القراءة أيضا.

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

وقال ذلك، ليست لدي مشكلة مع استخدام مؤشرات كقيم الحقيقة في حد ذاتها. فقط كما هو الحال مع NULL، انها لغة المتأصل.

وC ++ 09 سيضيف بناء على nullptr التي أعتقد أنها تأخرت كثيرا.

وأنا دائما استخدام 0. ليس لأي سبب من الأسباب الحقيقية مدروسة، لمجرد عندما كنت أول التعلم C ++ قرأت شيئا أن أوصى باستخدام 0 وأنا كنت دائما فعلت ذلك فقط بهذه الطريقة. من الناحية النظرية يمكن أن تكون هناك مشكلة التباس في القراءة ولكن في الواقع لم يسبق لي أن تأتي مرة واحدة في مثل هذه القضية في آلاف ساعة عمل والملايين من الأسطر من التعليمات البرمجية. كما يقول Stroustrup، انها حقا مجرد مسألة جمالية الشخصية حتى يصبح معيار nullptr.

قال لي أحدهم ذات مرة...سأقوم بإعادة تعريف NULL إلى 69.ومنذ ذلك الحين لم أستخدمه :P

فهو يجعل التعليمات البرمجية الخاصة بك ضعيفة للغاية.

يحرر:

ليس كل شيء في المعيار مثاليًا.الماكرو NULL هو ثابت مؤشر فارغ C++ محدد من قبل التنفيذ وغير متوافق تمامًا مع ماكرو C NULL، بالإضافة إلى إخفاء النوع ضمنيًا، يتم تحويله إلى أداة عديمة الفائدة وعرضة للأخطاء.

NULL لا يتصرف كمؤشر فارغ ولكن كحرف O/OL.

أخبرني أن المثال التالي ليس مربكًا:

void foo(char *); 
void foo(int); 
foo(NULL); // calls int version instead of pointer version! 

وبسبب كل ذلك، في المعيار الجديد يظهر std::nullptr_t

إذا كنت لا تريد انتظار المعيار الجديد وترغب في استخدام nullptr، فاستخدم على الأقل معيارًا لائقًا مثل المقترح بواسطة Meyers (انظر تعليق jon.h).

وحسنا أنا أزعم لعدم استخدام 0 أو فارغة مؤشرات على الإطلاق كلما أمكن ذلك.

<ع> استخدام لهم عاجلا أو آجلا سوف يؤدي إلى تجزئة أخطاء في التعليمات البرمجية. في تجربتي هذه، والمؤشرات في gereral هي واحدة من أكبر مصدر الخلل في C ++

وأيضا، فإنه يؤدي إلى البيانات "إذا-لا-فارغة" في جميع أنحاء التعليمات البرمجية. أجمل بكثير إذا كنت تستطيع الاعتماد على الدوام حالة صالحة.

ويكاد يكون دائما هناك بديل أفضل.

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

وأنا delt مؤخرا مع بعض الرموز مثل ذلك:

وvirtual void DrawTo(BITMAP *buffer) =0;

ولدالة الظاهري خالصة للمرة الأولى. فكرت أن يكون بعض jiberjash السحر لمدة أسبوع. عندما أدركت أنه كان مجرد وضع أساسا مؤشر الدالة إلى null (وظائف افتراضية وتعمل فقط المؤشرات في معظم الحالات لC ++) I ركل نفسي.

وvirtual void DrawTo(BITMAP *buffer) =null;

وكان يمكن أن يكون أقل مربكة من ذلك basterdation دون التباعد المناسب لعيني جديدة. في الواقع، وأنا أتساءل لماذا C ++ لا توظف null صغيرة مثل المبلغ الذي يوظف كاذبة صغيرة وصحيح الآن.

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