سؤال

أقوم حاليًا بإعادة إنشاء/ترتيب بعض رمز C القديم المستخدم في مشروع C ++ ، وأرى بانتظام وظائف مثل:

int f(void)

الذي أود أن أكتبه على النحو التالي:

int f()

هل هناك أي سبب لعدم استبدال (void) بـ () في جميع أنحاء قاعدة الشفرة من أجل تحسين الاتساق ، أم أن هناك فرقًا دقيقًا بين الاثنين اللذين لا أعرفهما؟ بشكل أكثر تحديدًا ، إذا تم وصف وظيفة عضو افتراضي في C ++ على النحو التالي:

virtual int f(void)

ويتضمن فئة مشتقة وظيفة عضو:

int f()

هل هذا تجاوز صحيح؟ بالإضافة إلى ذلك ، هل من المحتمل أن أواجه أي مشاكل في الارتباط بناءً على توقيعات متطابقة تقريبًا؟

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

المحلول

في C ، الإعلان int f(void) يعني وظيفة إرجاع int لا تأخذ أي معلمات. الإعلان int f() يعني وظيفة إرجاع int التي تأخذ أي عدد من المعلمات. وبالتالي ، إذا كان لديك وظيفة لا تأخذ أي معلمات في C ، فإن الأول هو النموذج الأولي الصحيح.

في C ++ ، أعتقد int f(void) تم إهماله ، و int f() هو مفضل ، لأنه يعني على وجه التحديد وظيفة لا تأخذ أي معلمات.

نصائح أخرى

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

على سبيل المثال ، الكود التالي يتوافق مع المعايير C:

#include <stdio.h>
void foo();
void bar(void) {
    foo();
}
void foo(int a) {
    printf("%d\n", a);
}

لكنه يؤدي إلى سلوك غير محدد ، منذ ذلك الحين a لم يتم تمريرها إلى foo.

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

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

أبرز:

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

C ++ ، من ناحية أخرى ، لا يميز بين الإعلانين ويعتبرهما كلاهما يعني وظيفة لا تأخذ أي وسيطات.

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

النماذج الأولية للوظيفة الفارغة هي ميزة تم إهمالها في C99 (كما كانت في C89).

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

تحرير 2: إضافة عرض أسعار من معيار C ++ ، القسم 8.3.5 ، الفقرة 2:

"إذا كان نقطة تراجع المعلمة فارغة ، فلا تأخذ الوظيفة أي وسيطات. قائمة المعلمات (void) تعادل قائمة المعلمات الفارغة. باستثناء هذه الحالة الخاصة ، يجب ألا يكون void نوعًا معلمة (على الرغم من أن الأنواع المستمدة من void ، مثل الفراغ*، العلبة). "

ليس هناك ذكر أن أي من النموذجين قد تم إهماله. شكرًا مرة أخرى على موقع السيد Tribble الممتاز لإشارةني إلى القسم الصحيح من المعيار.

TL ؛ DR: استخدام void.

بالنظر إلى التوافق المتخلف في C ++ ، وقليل من الغموض المحدد أدناه ، أؤكد أننا نعود طوال الطريق إلى KNR و ANSI C للحصول على إجابة قاطعة:

int getline(void);
int copy(void)

نظرًا لأن الإصدارات المتخصصة من GetLine و Copy لا تحتوي على وسائط ، فإن المنطق يشير إلى أن نماذجها الأولية في بداية الملف يجب أن تكون getline() و copy(). ولكن بالنسبة للتوافق مع برامج C الأقدم ، تأخذ المعيار قائمة فارغة كإعلان على الطراز القديم ، ويقوم بإيقاف فحص قائمة القائمة ؛ الكلمة void يجب استخدامه لقائمة فارغة بشكل صريح. [Kernighan & Richie ، The C Programming Language ، 1988 ، PGS 32-33

و..

يهدف المعنى الخاص لقائمة الوسيطة الفارغة إلى السماح لبرامج C القديمة بالتجميع مع المجمعين الجدد. لكنها فكرة سيئة لاستخدامها مع برامج جديدة. إذا كانت الوظيفة تأخذ الحجج ، أعلنها ؛ إذا لم يتطلب الأمر أي وسيطات ، فاستخدم void [Ibid ، pg. 73

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

C11 N1570 مسودة قياسية

void f() تم إهماله ، void f(void) مستحسن:

6.11.6 إعلانات الوظائف:

1 استخدام المعلمين للوظائف مع أقواس فارغة (وليس إعلانات نوع المعلمة النموذجية النموذجية) هو ميزة قديمة.

مقدمة:

2 بعض الميزات القادمة ، مما يعني أنه قد يتم النظر في الانسحاب في المراجعات المستقبلية لهذا المعيار الدولي. يتم الاحتفاظ بها بسبب استخدامها على نطاق واسع ، ولكن استخدامها في تطبيقات جديدة (لميزات التنفيذ) أو البرامج الجديدة (للغة [6.11] أو ميزات المكتبة [7.31]) لا يشجعها.

مناقشة مفصلة: https://stackoverflow.com/a/36292431/895245

C ++ 11 N3337 مسودة قياسية

لا هذا ولا ذاك void f(void) ولا void f() يتم إهمالها.

void f(void) موجود للتوافق مع C. الملحق C "التوافق" c.1.7 البند 8: إعلان:

8.3.5 التغيير: في C ++ ، لا تأخذ دالة مع قائمة معلمات فارغة أي وسيط. في C ، تعني قائمة المعلمات الفارغة أن رقم ونوع وسيطات الوظائف غير معروفين.

حيث void f() تم إهماله في ج و void f(void) مستحسن، void f(void) سوف توجد طالما يريد C ++ الحفاظ على التوافق.

void f(void) و void f() هي نفسها في C ++. لذلك كلما أطول void f(void) من المنطقي فقط إذا كنت تهتم بكتابة التعليمات البرمجية التي تجمع تحت كل من C و C ++ ، والتي من المحتمل ألا تستحق ذلك.

مناقشة مفصلة: https://stackoverflow.com/a/36835303/895245

في C ++ ، int f(void) هو في الواقع إعلان تم إهماله وهو ما يعادل 100 ٪ int f(). هو - هي هو نفس التوقيع. ال void في هذا السياق هو أمر مهم مثل المسافة البيضاء. هذا يعني أيضًا أنهم يخضعون لقاعدة التعريف الواحدة (لا يتم تحميلهم) و Derived::f(void) تجاوزات Base::f().

لا تعبث بأشياء مثل f(const void), ، على أية حال. ليس هناك الكثير من الإجماع الذي يعنيه هذا النوع من الغرابة.

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