В языке программирования C переменная может иметь адрес памяти и значение. И как я понял, каждая функция также имеет адрес, а также данные, которые выделяются по этому адресу. Мой вопрос в том, каков смысл данных, на которые указывают эти функции?данные зарезервированы в функции в C
ответ
Вы можете найти свой ответ here. Язык C поддерживает два вида распределения памяти через переменные в программах C:
- Статических распределения: что происходит, когда вы объявляете статический или глобальные переменные. Каждая статическая или глобальная переменная определяет один блок пространства фиксированного размера. Пространство выделяется один раз, когда ваша программа запускается (часть операции exec) и никогда не освобождается.
- Автоматическое распределение: происходит, когда вы объявляете автоматическую переменную, например аргумента функции в или локальной переменной. Пространство для автоматической переменной выделяется при вводе составного оператора, содержащего объявление, и освобождается при выходе этого составного оператора.
В GNU C размер автоматического хранилища может быть выражением, которое варьируется. В других реализациях C она должна быть константой.
Указатели функций концептуально не указатели данных. –
Язык программирования С (как и любой язык программирования) а спецификация (в некоторых докладе). Это не программное обеспечение. Вероятно, вы должны прочитать отчет n1570 (проект спецификации C11).
Концептуально, функция не имеет каких-либо данных в C (но его код может ссылаться на статические адреса, содержат буквенные константы - включая pointers- и т.д. ...). Он имеет некоторое поведение, которое практически реализуется некоторыми кодом. Что такое код не определяется стандартом C.
Практически говоря, и это зависит от конкретной реализации (смотреть на разницу между Harvard машины & computer architectures и Von Neumann из них), указатель на функцию некоторый адрес machine code (часто мишенью для CALL
machine instruction перевод вызовов C к нему).
На рабочих столах & ноутбуков & таблетки с некоторой обычной операционной системой (например, Linux, Windows, MacOSX, прошивка, Android ...) -всом являются фон Нейман архитектура: x86-64 или АРМЫ, ваш процесс имеет один virtual address space содержащие code segments и data segments и данные кучи. Тогда указатели функций и указатели данных имеют один и тот же вид, и это практически, что значимо для их броска. Канонический пример - использование POSIX dlsym: вы часто приводите его результат к некоторому указателю функции (например, внутри некоторого plugin, который является dynamically loaded с dlopen). Адрес функции - , фактически говорящий адрес его первой машинной инструкции (сидящий в некотором сегменте кода в общем адресном пространстве). Прочитано this & that для творческих примеров.Другим полезным примером являются JIT compilation библиотеки, такие как asmjit, GNU lightning, libgccjit, LLVM: они позволяют генерировать машинный код во время выполнения и получать от них (свежую) функцию. Ни dlsym
, ни JIT библиотеки в строгом смысле соответствует стандарту C, так как в чисто стандартной программе, соответствующие C множество функций статический известно и любая функция указатель должен указывать на какую-существующого функции тех же сигнатуры (читайте около calling conventions & ABI s), в противном случае это undefined behavior.
На некоторых embedded computers с архитектурой Гарварда (например, Arduino) код и данные размещаются в разных пространствах, а адрес кода может не иметь того же количества бит, что и адрес данных. В таких системах литье между функциями и указателями данных бессмысленно (если вы не погрузитесь в детали глубокой реализации). Стандарт C был определен как достаточно общий, чтобы учитывать такие странные компьютеры.
Читайте также много о closures и continuations. Стандарт C их не имеет (следовательно, callbacksусловно взять некоторый аргумент данных клиента). Вероятно, вы узнаете много, прочитав SICP. Читайте также о homoiconicity.
Читайте также о Operating Systems: Если вы используете Linux (который я рекомендую, потому что это в основном из free software, исходный код вы можете изучить), прочитать Advanced Linux Programming. Читайте также Operating Systems: Three Easy Pieces.
Другими словами: ваш вопрос (по указателям функций и адресам) имеет разные подходы. Догматический подход к программированию на языке программирования (и проблема заключается в глубоком понимании указателей функций в стандартах C CompCert & Frama-C); прагматичная операционная система и конкретный подход к внедрению (а затем это зависит от вашего компьютера, его instruction set и его ОС и даже ваших флагов C compiler - и версии - и optimization, и вы можете даже иметь некоторые «магические механизмы» - например, dlsym
& dlopen
или библиотеки компиляции JIT - создают функции во время выполнения, что составляет magic, потому что стандарты C не думают об этом).
Вы уже получили (хорошие) ответы, но я думаю, что некоторые (неясно?) Факт о С следует отметить, что касается вашего вопроса:
В языке программирования C, переменная может иметь адрес памяти и значение.
На самом деле определяющее свойство переменного является то, что всегда имеет значения - если это неинициализированное, семантический она все еще имеет значение, только то, что это значение является «неопределенным значением» и чтение «неопределенного значения "вызывает неопределенное поведение.
Но, это важно, но не каждая переменная в C имеет адрес! Существует этот небольшой классификатор хранения register
, который точно означает, что большинство людей не полностью понимают. Наиболее распространенная и неправильная интерпретация заключается в том, что register
означает, что переменная должна помещаться только в регистры.Проблема заключается в том, что существуют архитектуры команд, в которых регистры не существуют, но C был разработан для того, чтобы быть по-прежнему жизнеспособным для них.
Истинный смысл register
классификатора есть, что вы не можете взять адрес переменных, которая является регистром, что означает, что вы не можете создавать указатели к нему.
. Результатом этого является то, что переменная, которая равна register
, имеет значение только для нее. И вполне логично, чтобы компилятор C генерировал код, который полностью отбрасывает «место» (будь то регистр, местоположение памяти или что-то совсем другое), где его значение пришло, если оно способно верно воссоздать значение в что семантически соответствует тексту программы. Это также означает, что вполне законно выполнять полное перерасчет того, что должно было быть выполнено для получения окончательного значения. Вот почему применение квалификатора хранилища register
к переменной может привести к резкому увеличению размера кода и капля производительности.
В качестве такого классификатора register
хранений не является механизм для оптимизации кода, но должен рассматриваться как инструмент специального назначения для написания кода, который не является ни время, ни размером критическим, но должен работать при очень специфических, жестких ограничениях. Одним из примеров может быть, например, загрузчик или код инициализации системы, задача которого состоит в том, чтобы инициализировать доступ к памяти в первую очередь и работать с несколькими байтами - или даже без - полезной памяти, но может повторно вычислять требуемые значения для каждого шага.
Вопрос был больше о указателях функций, чем о переменных. –
@BasileStarynkevitch: Да, но само название вопроса не совсем ясно. Люди, которые задаются вопросом о том, «где переменные в области функций» (ака автоматическое хранилище) проживают, могут преодолеть этот вопрос. И я чувствовал, что определенная подтема также требует рассмотрения. – datenwolf
Указатели функций указывают на блоки команд машины, которые выполняются при вызове функции.
Скажем у вас есть это:
#include <stdio.h>
int plus_42(int x)
{
int res=x+42;
printf("%d + 42 = %d\n", x,res);
return res;
}
int main()
{
return plus_42(1);
}
Если вы скомпилировать его, связать его и запустить objdump -d на результат:
gcc plus_42.c && objdump -d a.out
вы получите (в зависимости от вашей архитектуры, что-то вроде:
0000000000400536 <plus_42>:
400536: 55 push %rbp
400537: 48 89 e5 mov %rsp,%rbp
40053a: 48 83 ec 20 sub $0x20,%rsp
40053e: 89 7d ec mov %edi,-0x14(%rbp)
400541: 8b 45 ec mov -0x14(%rbp),%eax
400544: 83 c0 2a add $0x2a,%eax
400547: 89 45 fc mov %eax,-0x4(%rbp)
40054a: 8b 55 fc mov -0x4(%rbp),%edx
40054d: 8b 45 ec mov -0x14(%rbp),%eax
400550: 89 c6 mov %eax,%esi
400552: bf 04 06 40 00 mov $0x400604,%edi
400557: b8 00 00 00 00 mov $0x0,%eax
40055c: e8 af fe ff ff callq 400410 <[email protected]>
400561: 8b 45 fc mov -0x4(%rbp),%eax
400564: c9 leaveq
400565: c3 retq
0000000000400566 <main>:
400566: 55 push %rbp
400567: 48 89 e5 mov %rsp,%rbp
40056a: bf 01 00 00 00 mov $0x1,%edi
40056f: e8 c2 ff ff ff callq 400536 <plus_42>
400574: 5d pop %rbp
400575: c3 retq
400576: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40057d: 00 00 00
plus некоторые шаблоны.
Здесь 0000000000400536
и 0000000000400566
являются адреса main
и plus_42
(= указатели, которые main
и plus_42
пункт), соответственно, и шестнадцатеричные числа, которые вы видите во 2-м столбце данные, которые декодируются в 3d колонке в человеческие читаемые имена машинных инструкций, которые представляют данные.
Я бы предложил вместо этого скомпилировать с 'gcc -S -fverbose-asm -O plus_42.c' и изучить испущенный' plus_42.s' –
@BasileStarynkevitch Спасибо за предложение. Я чувствую фактическую сборку с гексами, а фактические (несимвольные) адреса лучше иллюстрируют мою точку зрения. – PSkocik
- 1. На какой стадии компиляции зарезервированы идентификаторы зарезервированы?
- 2. Когда ключевые слова C# не зарезервированы?
- 3. Автономные функции/данные в C++
- 4. Is: apps/'apps' зарезервированы в Rails v4?
- 5. Названия методов класса Ruby зарезервированы
- 6. Имена переменных Javascript, которые зарезервированы.
- 7. C++ вектор теряет данные в рекурсивной функции
- 8. Храните дополнительные данные в указателе функции c
- 9. Почему имена встроенных типов Python не зарезервированы?
- 10. Какие ключевые слова зарезервированы в JavaScript, но не в Java?
- 11. C# Lambda Функции: возвращающие данные
- 12. суммировать данные в функции вместо
- 13. Обработка SQL зарезервированы имена таблиц и столбцов
- 14. Имена XSL PI, начинающиеся с XML, зарезервированы
- 15. C функции в C++
- 16. данные значения аргументов изменяются в теле функции в C++
- 17. Общие данные в C
- 18. C# Данные в EventHandler
- 19. Функции сопоставления в C++
- 20. функции внутри функции в C
- 21. Функции внутри функции в C
- 22. вызов функции в другой функции в C
- 23. Помогите маршалинг функции C в C#
- 24. Ошибка функции сна В C
- 25. Преобразование функции C в C++
- 26. C++ функции в Objective C
- 27. Как использовать форвардные объявленные данные в шаблоне функции? (C++)
- 28. C: Возврат функции, указывающей на данные в памяти
- 29. Пытается возвращать входные данные от функции в C
- 30. Данные таблицы фильтра в функции
Этот вопрос может касаться внутреннего представления функций и указателей функций. Ну, все детали зависят от платформы (особенно учитывая общие библиотеки/библиотеки DLL). –