Чи не потрібна крапка з комою (';') після оголошення функції в C ++?


174

Нещодавно я пройшов проміжний тест програмування, і одне з питань, що я помилився, полягав у наступному:

Точка з комою (';') після оголошення функції не потрібна.

Правда чи неправда.

Я вибрав "false" (і, будь ласка, виправте мене, якщо я помиляюся, тому що я відчуваю, що я збуваю з розуму), декларація функції - це те, що ви пишете перед визначенням (у верхній частині коду), щоб компілятор знав функцію виклик, перш ніж навіть викликати його, і визначення функції - це те, що складає функцію в цілому.

Тобто,

Декларація:

int func();

Визначення:

int func() {
  return 1;
}

Чи не повинна відповідь на це бути хибною?


41
Визначення - це також декларація. Але я б сказав, що ваша відповідь була правильною.

216
Це складне запитання, яке не має стосунку до здатності кого-небудь добре програмувати.
телефонінг

40
Я завжди знаходжу питання, які призводять до подвійних негативів, заплутаних. На мій погляд, такі питання розроблені для подолання студентів. Чому питання не можна сформувати таким чином: "Точка з комою (';') завжди потрібна після оголошення функції. Правда чи помилково."? : /
Альгерд Преіджіус

18
@phonetagger Вся ця плутанина показує, наскільки погано сформульовано питання.
Франсуа

34
Бритва Ханлона припускає, що автор тесту змішав "декларацію" та "визначення".
Sneftel

Відповіді:


161

У вас може виникнути ситуація, коли ви оголосите та визначите функцію за один крок, тобто якщо ви включите визначення функції в точку, де ви її декларуєте. Тож технічно я вважаю, що це правда. Але питання сформульовано таким чином, що я відповів би на нього так, як ви.


10
Я б стверджував, що правда не вірна через причину, яку ви назвали. Якщо є випадки, коли потрібна крапка з комою, то вона помилкова (або не відповідає дійсності). Правда це абсолют для мене, якщо є явні випадки, коли це потрібно, то ви не можете сказати правду.
I Футбол

16
@IFunball Хороший аргумент. Дурні віртуальні мови. Речення "Точка з комою (';') не потрібна після оголошення функції" може розглядатися як "Точка з комою (';') не потрібна (ніколи) після оголошення функції" або як "Точка з комою (';") ) не потрібен (завжди) після оголошення функції ". Чи слід кваліфікувати твердження як істинне чи помилкове, що залежить від вибору тлумачення. Суворо сказане питання є незрозумілим і, отже, не має чіткої відповіді.
Пітер -

6
@IFunball Це тому, що "декларація", без подальшого контексту і жодної заяви про те, що ми займаємось мовою, зазвичай позначається як "дефініційна декларація". Питання було несправедливим.
Гонки легкості по орбіті

2
Будь-яке питання, яке незрозуміло для того, хто знає, на який тестується вміст, помиляється.
Нат

2
Здається, нам потрібно додати до англійської мови невизначене положення про поведінку
Нік

147

На додаток до речі "визначення також є декларацією", юридичне C ++:

int f(), g();

Це декларує дві функції, fі gбез аргументів, і з типом повернення int, але визначення fне супроводжується (негайно) крапкою з комою. Так само це законно:

int f(), i = 42;

Але насправді не дозволяється пропускати крапку з комою цілком у цих випадках, тому було б дещо дивно, якби будь-який був взятий за приклад декларації без наступної крапки з комою. Насправді, таке незаконне:

void *p, f() {}

Окрім (просто) оголошення функції, визначення функції не може поєднуватися з будь-яким іншим оголошенням або визначенням до того ж специфікатора типу . (Якби це було законно, воно визначало б void *pі а void f() {}).

У будь-якому випадку, здається, це питання типу "gotcha", яке не повинно бути в проміжному тесті програмування.

(О, до речі, будь ласка, не пишіть насправді подібний код int f(), i = 42;.)


2
Також можна використовувати typedef для визначення типу функції, а потім скористатися цим, щоб оголосити багато функцій відразу, наприклад, typedef int fooProc(int); fooProc a,b.c.d.e;я не впевнений, чому стандартні заголовки для компіляторів на основі дискети не зробили цього ще в день, оскільки я думаю, що це дозволило б файлів заголовків бути набагато меншими і, таким чином, швидше обробляти.
Supercat

Також врахуйте, що в ньому int f(int(&g)(),int(*h)()){return g()+h();}є три функції оголошення, за однією з яких йде відкрита фігурна дужка, інша - комою, а третя - близькою дужкою.
Девід

1
@DavidHammen: Це не чітко оголошує інші функції, крім int f(stuff). Навіть у межах функції, gце автоматична змінна типу посилання на функцію та hє вказівником на функцію .
Пітер Кордес

83

В інших відповідях та коментарях випливає кілька із багатьох способів, що це жахливе, оманливе і погано написане питання. Але є ще одна проблема, яку ще ніхто не визначив. Питання:

Точка з комою (';') після оголошення функції не потрібна. Правда чи неправда.

Добре, давайте розглянемо декларацію функції:

int func();       /* */
/*           ^       */
/*           |       */
/* That whitespace is "after the function declaration". */

Вся ця річ - декларація . Декларація не є, int func()а потім слідує a ;. Після декларації йде int func();пробіл.

Отже, питання: чи потрібна крапка з комою після декларування ? Звичайно, ні. У декларації вже є крапка з комою, яка припинила її. Точка з комою після декларації була б безглуздою. Навпаки, після оголошення функціїint func(); ; буде крапка з комою .

Питання майже напевно мало на меті задати питання "правдивим чи неправдивим: останній маркер у оголошенні функції завжди є крапкою з комою", але це не те питання, яке вони написали, тому що автор вікторини чітко не замислювався над проблемою.

Моя порада взагалі уникати вікторин мови програмування. Вони досить жахливі.


Веселий факт, поки ми на тему. У C # це все законно:

class C {}
class D {};
struct E {}
struct F {};

У C # декларація класу чи структури може закінчуватися крапкою з комою або на ваш розсуд чи ні. Ця дивна маленька функція була додана на користь програмістів на C / C ++, які приїжджають до C #, які мають у своїх руках, що декларації типу закінчуються безглуздим крапкою з комою; команда дизайнерів не хотіла карати їх за звичку. :-)


Коментарі не для розширеного обговорення; ця розмова була переміщена до чату .
Samuel Liew

25

Ви також можете оголосити таку функцію:

int func(){
    return 1;
}

Заява дуже неоднозначна. Правильна відповідь повинна бути: це залежить від того, як ви оголосите функцію.

У будь-якому випадку я вибрав би помилкове, і, можливо, ви можете повідомити про це питання комусь.


3
У будь-якому випадку, не ставте річ на особистому рівні. Важливим є те, що ви зрозуміли, як працює визначення декларації функції, тому не переживайте над цим занадто сильно, просто переконайтесь, що питання буде хоча б перевірено і продовжуйте
Лука Корсині

11
Абсолютно. Чесно кажучи, я дізнався більше про декларацію функції про те, щоб помилитися з питанням, ніж я вважав би, що я зрозумів це правильно.
Логан

1
@Logan не дуже хвилюйся Якщо ви вмієте писати та читати функцію, це все, що вам потрібно. Я особисто ненавиджу такі питання, які 1. недостатньо чітко визначені 2. перевірити свої теоретичні знання про синтаксис. Для мене це як м'язова пам’ять. Коли я пишу кожну цифру, без зусиль переходить до клавіші, яку вона повинна перейти, але якщо ви дасте мені тест про те, які клавіші слід натискати на цифру, я б абсолютно безперспективно без клавіатури, щоб фізично зробити дію ...
bolov

2
... Написання загального синтаксису (наприклад, як функція) стане для вас другою природою. І коли ви зіпсуєте це, тому що ви просто перейшли на мову, ну ... інтелігенція та підсвічування синтаксису дозволяють зробити швидкі та ефективні рішення. Вкладіть свій час і енергію в щось більш корисне.
болов

20

Точка з комою (';') після оголошення функції не потрібна.

Правда чи неправда.

Правда . Точка з комою не потрібна після жодного оголошення. Ні після жодного визначення. Ні після жодної заяви.

Багато видів оголошення повинні закінчуватися крапкою з комою, як зазначено в синтаксисі у розділі 7 [dcl.dcl]. Але ніколи не потрібно писати другу після цього.


1
Я бачу, що Ерік Ліпперт вже аргументував це. Я здогадуюсь, що всі відгуки змусили мене не помітити це. Сміливо віддавайте свої голоси там.
Марк ван Левен

Насправді будь-яке запитання, яке задає: "X завжди правда: правда чи хибність?" матиме відповідь "помилково". Чорт забирай, нікуди не потрібно мати крапки з комою ; компілятор може скаржитися та відмовлятись у складанні вашої програми, але навряд чи це кінець світу; Я б не назвав це принциповою потребою . ;)
Quuxplusone

@Quuxplusone, якщо компілятор відхиляє вашу програму, у вашій програмі немає жодних декларацій функцій в ній :)
Ben Millwood,

6

Це залежить від того, заявляємо ми чи визначаємо функцію. Якщо ми оголошуємо функцію, нам потрібно включити крапку з комою ( ;), а якщо ми визначаємо функцію, крапка з комою не потрібна.

Декларація така:

int add(int, int);

І визначення таке:

int add(int a, int b)
{
    // ...
}

10
Проблема цієї відповіді полягає в тому, що вона говорить про те, що визначення та декларація є взаємовиключними. Насправді кожне визначення - це декларація; визначення - це підмножина декларацій.
MSalters

6

Незважаючи на те, що я погоджуюся з майже всіма іншими відповідями, заявивши, що це питання дуже неоднозначне і що ваша відповідь технічно правильна, дозвольте мені дати іншу точку зору:

Ось як я завжди їх називав:

void func();  // The function prototype

...

void func()
{
    // The function definition
}

Я припускаю, що питання було складено з урахуванням цієї термінології.

Визначення та декларація - це те саме поняття в моїх очах. "Я визначаю x = y" == "Я оголошую x = y".

Але звичайно, існує велика різниця між прототипом функції (вгорі) і фактичним визначенням функції.


Для мене ваш прототип - це декларація, заснована на тому, як я дізнався (не кажучи, що ви також неправі), але тоді я також очікував, що прототип вкаже кількість і тип аргументів, або недійсний, але я очікую, що ви пропустили це для стислості
David S

Девід S: Так, звичайно, він також містив би кількість та тип аргументів, але я дійсно їх коротко опустив (зауважте, що аргументів також немає у фактичній декларації функції). Однак я не дуже згоден, коли ви говорите, що повне функціонування називається прототипом. Я цитую Вікіпедію: "Прототип функції або інтерфейс функції - це оголошення функції, яка визначає ім'я та тип функції підпису (сутості, типи даних параметрів та тип повернення), але опускає тіло функції".
Opifex

@DavidS: У C ++ декларації функції завжди є прототипами (або визначеннями) і void func();точно еквівалентні void func(void);. Це дуже відрізняється від C , де void func();компілятор нічого не повідомляє про аргументи, і це не те саме, що void func(void);. Пізніший прототип або визначення - хороша ідея, інакше абонент повинен застосувати промоції аргументів за замовчуванням (наприклад, float -> double та вузькі цілі типи до int. Ті ж правила, що і для аргументів для різних функцій.)
Пітер Кордес,

Вибачте, я опинився тут на щось, що стосується С, і не зазначив зміни мови. Я не видаляю свій коментар з метою ясності, але вважаю його відкликаним.
David S

6

Шкода, що питання, яке ви взяли, не говорить "безпосередньо після". Ми могли б, наприклад, написати це:

int func()  /* My function */ ;

Або я можу написати:

int func()
int a = 42;

У першому випадку крапка з комою знаходиться не безпосередньо після оголошення, але це було б добре.

У другому випадку є крапка з комою "після" декларації, але не безпосередньо після.

Я думаю, що Ерік Ліпперт має правильну ідею у своїй відповіді .

Це як би сказати "чи повинен бути період після закінчення речення англійською мовою?". Можливо, у речення вже є період у кінці (інакше це не було б вироком), і тому після вироку не повинно бути періоду .


4
Приємно. Закінчуючи це речення додатковим періодом. Я бачу, що ви там робили.
David S

2
int func() int a=42;не компілюється. Вам потрібна кома, а не інша int. Дивіться відповідь @ Арна, опубліковану за добу до цього. Єдине нове у цій відповіді - останній абзац з аналогією до англійських речень.
Пітер Кордес

1
Я не сказав другого складеного прикладу. Я вказував, що сказати, що крапка з комою потрібна "після" декларації, була неоднозначною. Мій приклад мав крапку з комою після декларації, але вона не складається.
Нік Гаммон

1
Ця ж проблема виникає і в повідомленнях про помилки; улюблений приклад з C # - " Параметр params повинен бути останнім параметром у формальному списку параметрів ". Тепер, припустимо, замість цього я сказав: "Жаб повинен бути останнім глобусом у списку глобусів". Чи означає це (1) Кожен список глобусів має рівно один жаб на кінці, як і кожне запитання має рівно один знак запитання на кінці, (2) У списку глобусів може бути будь-яка кількість жаб, але якщо у нього є одна чи декілька жаб , останній елемент повинен бути фробом, як парне число може мати будь-яке число 02468, але одна з обов'язкових повинна бути останньою, або ...
Ерік Ліпперт

... (3) у списку глобусів може бути нуль або одна лялька, а якщо вона є, вона приходить наприкінці? Якщо ви не знаєте контексту, я думаю, що (1) є найбільш розумним поясненням, але у випадку "параметра парам", (3) - правильне пояснення. Багато неофіційних описів елементів мови програмування мають властивість, яку мої друзі технічного редактора називають "COIK" - Очистити, лише якщо відомо. Якщо ви ще не досконало розумієте матеріал, опис його вам марний, але якщо ви його вже добре розумієте, опис вам не потрібен!
Ерік Ліпперт

4

Ви можете використовувати ;лише для прототипів.


4

Це щось складне запитання, але вони використовували слово декларація, яке означає щось подібне:

int example();

Так що в цьому випадку це правда.

Якби вони використовували слово реалізацію, то це було б помилково.


2

Точка з комою (;) використовується для того, щоб сказати компілятору, що після цього крапки з комою (;) починається новий вислів.

Тому я вважаю, що крапка з комою (;) потрібна лише під час оголошення функції. Тож, на мою думку, відповідь буде правдою.


Декларації, проте, не є заявами.
HolyBlackCat

але після оголошення функції ми виконуємо новий рядок коду за допомогою компілятора. тому я думаю, перед тим, як виконати новий рядок компілятора коду, треба знати, де закінчується попередній рядок коду, тоді компілятор може генерувати власний код (тобто 0101).
Джатіндер

2

Коли функції визначені перед main () :

  • Точка з комою не потрібна, оскільки функція вже визначена

Коли функції визначені після main () :

  • Вам потрібна крапка з комою, тому що ви прототипуєте цю функцію і повідомляєте компілятору, що функція завершується.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.