Почему размер функции в C всегда равен 1 байту?

87

Когда мы проверяем размер функции с помощью sizeof(), мы всегда получаем 1 байт . Что означает этот 1 байт?

user1645461
источник

Ответы:

80

Это нарушение ограничения, и ваш компилятор должен его диагностировать. Если он компилирует его, несмотря на это, ваша программа имеет неопределенное поведение [спасибо @Steve Jessop за разъяснение режима отказа и см. Ответ @Michael Burr о том, почему некоторые компиляторы допускают это]: из C11, 6.5.3.4./ 1:

sizeofОператор не должен быть применен к выражению , которое имеет тип функции

Керрек С.Б.
источник
11
Это ограничение, что означает, что оно диагностируется соответствующим компилятором. Если компилятор все равно его компилирует (диагностировав), поведение не определено. Если компилятор не диагностирует его (что, например, не обходится в gcc -pedantic), значит, у вас несовместимый компилятор, и каждая программа имеет неопределенное поведение.
Стив Джессоп,
1
В путы поведение его в той же категории, что и расширения GNU C, но я понятия не имею , почему кто -то хочет , что поведение, так что я не знаю , почему авторы GNU вышли из своего пути , чтобы добавить его.
Стив Джессоп,
1
@SteveJessop: Обратите внимание, что это даже с -std=c11, а не gnu11 . Это действительно странное расширение компилятора.
Kerrek SB
6
Ой! Бьюсь об заклад, это включить арифметику для указателей функций, так же, sizeof(void)как 1 в GNU C.
Стив Джессоп
3
По поводу -std=c11: кто-то должен сослаться на -std=c*варианты в Стандарты рекламы. Они не включают режим соответствия, они просто отключают расширения, которые могут помешать компиляции правильно сформированной программы (например, typeofбыть ключевым словом, поскольку правильно сформированная программа на C может использовать его как имя переменной, но gccпо умолчанию отклоняет это ). Чтобы дополнительно отключить расширения, которые позволяют плохо сформированным программам проходить без диагностики, вам понадобится -pedanticили -pedantic-errors.
Стив Джессоп,
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

Вы можете заставить GCC выдавать предупреждение при использовании sizeofс этими операндами, используя опции -pedanticили -Wpointer-arithдля GCC. Или сделайте ошибку с помощью -Werror=pointer-arith.

Майкл Берр
источник
Ваша логика ошибочна. C требует диагностических сообщений для некоторых, но не для всех UB. Вы не можете утверждать, что что-то определило поведение только потому, что есть диагностика.
MSalters
4
C требует диагностики для всех нарушений ограничений (5.1.1.3 Диагностика в C99 или C11). Ограничение (3.8 в C99 / C11) - это «ограничение, синтаксическое или семантическое, с помощью которого должно интерпретироваться описание языковых элементов», которое, кажется, говорит о том, что то, что не соответствует ограничениям, не может быть интерпретировано .
Майкл Берр,
3
И для ясности - нарушение ограничения не приводит к неопределенному поведению. Это ошибка, похожая на синтаксическую ошибку. Например, в стандарте сказано: «если нарушается требование« должен »или« не должен », которое появляется вне ограничения , поведение не определено». Если нарушение ограничения приведет к UB, почему в стандарте говорится только о «разрешенных» и «недопустимых», которых здесь нет в ограничениях?
Майкл Берр,
3
Я действительно ничего не sizeofговорил о UB, за исключением того, что функция не является UB (о чем я упоминал в значительной степени только потому, что в других ответах говорилось, что это UB). Но, возможно, я запутал это из-за того, как я построил предложение. Чтобы было понятнее. sizeofфункция не является UB (как утверждается в нескольких ответах). Это нарушение ограничения. Таким образом, требуется диагностика. GCC разрешает это как расширение.
Майкл Берр,
2
@KerrekSB: OP не получает диагностику, потому что предположительно они используют GCC, который разрешает это использование в качестве расширения языка C.
Майкл Берр,
13

Это означает, что автор компилятора выбрал значение 1 вместо того, чтобы заставить демонов летать из вашего носа (действительно, это было еще одно неопределенное использование, sizeofкоторое дало нам это выражение: «сам компилятор C ДОЛЖЕН выдать диагностику, ЕСЛИ это первое требование диагностика в результате вашей программы, а затем МОЖЕТ сама вызвать демонов, вылетающих из вашего носа (что, кстати, вполне может БЫТЬ документированным диагностическим сообщением), точно так же, как МОЖЕТ выдать дополнительную диагностику для дальнейших нарушений синтаксических правил или ограничений (или, в этом отношении, по любой причине, которую он выберет). " https://groups.google.com/forum/?fromgroups=#!msg/comp.std.c/ycpVKxTZkgw/S2hHdTbv4d8J

Отсюда есть жаргонный термин «назальные демоны» для обозначения того, что компилятор решает сделать в ответ на неопределенную конструкцию. 1- назальный демон этого компилятора для этого случая.

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

Как указывали другие, sizeof () может принимать любой действительный идентификатор, но он не возвращает действительный (честно истинный и действительный) результат для имен функций. Кроме того, это определенно может или не может привести к синдрому «демонов из носа».

Если вы хотите профилировать размер функции вашей программы, проверьте карту компоновщика, которую можно найти в каталоге промежуточных результатов (тот, где вещи компилируются в .obj / .o или где находится результирующее изображение / исполняемый файл). Иногда есть возможность сгенерировать или нет этот файл карты ... он зависит от компилятора / компоновщика.

Если вам нужен размер указателя на функцию, все они имеют одинаковый размер, размер адресного слова на вашем процессоре.

jpinto3912
источник
1
Что за утверждение "определенно может или не может" ??? Разве это не верно буквально для всего?
Kerrek SB
@KerrekSB: да, но здесь он может что-то делать, а может и не делать, и при этом оставаться в рамках правил. Это правда, что компилятор может или не может отказаться от компиляции, int x = 1;но только один из них разрешен для компилятора, совместимого со стандартами. При sizeof()применении к функции он может или не может возвращать установленное значение, или отказываться от компиляции, или возвращать случайное значение, основанное на том, что находится в конкретном регистре в то время. Буквальные носовые демоны маловероятны, но в пределах буквы стандарта.
Джон Ханна,
@kerrek Это может быть правдой ни для чего, а может и не быть ложью ... смотри на это как на нечеткую нелогичность.
jpinto3912
1
Если вы хотите узнать размер указателя на функцию, примените sizeofк указателю на функцию.
Alexis