Чому розмір функції в C завжди 1 байт?


87

Коли ми перевіряємо розмір функції за допомогою sizeof(), ми завжди отримуємо 1 байт . Що означає цей 1 байт?

Відповіді:


80

Це порушення обмеження, і ваш компілятор повинен його діагностувати. Якщо вона скомпілює це, незважаючи на це, ваша програма має невизначену поведінку [спасибі @Steve Jessop за роз'яснення режиму відмови і див. Відповідь @Michael Burr, чому деякі компілятори це дозволяють]: З C11, 6.5.3.4./ 1:

sizeofОператор не повинен бути застосований до вираження , яке має тип функції


11
Це обмеження, що означає, що у відповідному компіляторі він діагностований. Якщо компілятор все-таки компілює його (поставивши діагноз), тоді поведінка не визначена. Якщо компілятор не діагностує його (чого, наприклад, gcc не без -pedantic), у вас є невідповідний компілятор, і кожна програма має невизначену поведінку.
Steve Jessop

1
Поведінка ставить його до тієї самої категорії, що і розширення GNU C, але я не уявляю, чому хтось хоче таку поведінку, тому я не знаю, чому автори GNU намагалися додати її.
Steve Jessop

1
@SteveJessop: Зверніть увагу, що це навіть з -std=c11, ні gnu11 . Це справді дивне розширення компілятора.
Kerrek SB

6
Ох! Б'юся об заклад, це дозволити арифметику на покажчики функцій, так само, sizeof(void)як 1 у GNU C.
Стів Джессоп,

3
Щодо -std=c11: хтось повинен звернутися до -std=c*варіантів із рекламними стандартами. Вони не вмикають режим відповідності, вони просто відключають розширення, які заважали б сформованій програмі компілюватися (наприклад, typeofбути ключовим словом, оскільки добре сформована програма C може використовувати його як ім'я змінної, але gccза замовчуванням це відхилить ). Щоб додатково вимкнути розширення, які дозволяють неправильно сформованим програмам проходити недіагностику, потрібно -pedanticабо -pedantic-errors.
Steve Jessop

56

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

Однак, як розширення мови C, GCC дозволяє включати арифметику void покажчики та покажчики на функції, що робиться шляхом обробки розміру a voidабо функції як 1. Як наслідок, sizeofоператор оцінить 1для voidабо функцію з GCC. Див. Http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html#Pointer-Arith

Ви можете отримати ПКУ видавати попередження при використанні sizeofз цими операндами, використовуючи -pedanticабо -Wpointer-arithваріанту GCC. Або зробіть помилку з -Werror=pointer-arith.


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

4
C вимагає діагностики всіх порушень обмежень (5.1.1.3 Діагностика в C99 або C11). Обмеження (3.8 у C99 / C11) - це "обмеження, синтаксичне чи семантичне, за допомогою якого слід інтерпретувати виклад мовних елементів", що, здається, говорить про те, що те, що не відповідає обмеженням, не може бути інтерпретоване .
Michael Burr

3
І щоб бути зрозумілим - порушення обмеження не призводить до невизначеної поведінки. Це помилка, як синтаксична помилка. Наприклад, стандарт говорить: "якщо вимога" повинен "чи" не повинен ", яка з'являється поза обмеженням , порушується, поведінка невизначена". Якщо порушення обмеження призведе до UB, чому стандарт буде говорити лише про "дозвіл" та "не допущення", які тут не обмежені?
Michael Burr

3
Я дійсно нічого не sizeofговорив про UB, окрім того, що функція не є UB (про що я згадав майже лише тому, що інші відповіді стверджували, що це UB). Але, можливо, я заплутав це через те, як я структурував речення. Щоб бути більш чітким. sizeofфункція не є UB (як стверджували кілька відповідей). Це порушення обмеження. Як такий, він вимагає діагностики. GCC дозволяє це продовження.
Майкл Берр

2
@KerrekSB: OP не отримує діагностики, оскільки, мабуть, вони використовують GCC, що дозволяє це використання як розширення мови C.
Michael Burr

13

Це означає, що автор компілятора визначився із значенням 1, а не змусив демонів злітати з носа (справді, це було черговим невизначеним використанням sizeof дало нам такий вираз: "сам компілятор С ПОВИНЕН видати діагностику, ЯКЩО це перше, що потрібно діагностика, отримана в результаті вашої програми, а потім МОЖЕ привести до того, що демони вилітають з вашого носа (що, до речі, цілком може бути документальним діагностичним повідомленням), так само, як МОЖЕ видати подальшу діагностику щодо подальших порушень правил синтаксису або обмежень (або, з цього приводу з будь-якої причини). " https://groups.google.com/forum/?fromgroups=#!msg/comp.std.c/ycpVKxTZkgw/S2hHdTbv4d8J

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


@IlmariKaronen, хоча мені доведеться визнати, що є причина, що більшість моїх відповідей на C (та C ++) стосуються або загальних мовно-агностичних принципів, або подібних історичних самородків. Мій досвід C межує з історичним сам по собі :)
Джон Ханна,

7

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

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

Якщо вам потрібен розмір вказівника на функцію, вони мають однаковий розмір, розмір адресного слова на вашому процесорі.


1
Що це за твердження "це однозначно може чи не може" ??? Хіба це не так буквально про все?
Kerrek SB

@KerrekSB так, але тут він може щось робити, а може і не робити, і все одно дотримуватися правил. Це правда, компілятор може або не може відмовити у компіляції, int x = 1;але для компілятора, що відповідає стандартам, допускається лише один із них. Сsizeof() застосовуються до функції, він може або не може повертати задане значення, або відмовитися від компіляції, або повертає випадкове значення , засноване на те , що це в певному регістрі в той час. Буквальні носові демони малоймовірні, але в межах букви стандарту.
Jon Hanna,

@kerrek Це може бути правдою ні для чого, а може бути неправдою ні для чого ... дивіться на це як на нечітку нелогічність.
jpinto3912

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