Перейти к содержанию
    

Народ, такая проблема. Необходимо при компиляции определить сколько раз вызывается функция (foo), а так же передать переменную из препроцессора(скрипта) в код программы.

:1111493779:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

#!/bin/sh

COUNT=0

for FILE in *.c
do
    CURR=`cpp -E ${FILE} | grep -vv "^#" | grep "foo(" | grep -vv -c "void foo("`
    COUNT=`expr ${COUNT} + ${CURR}`
    echo -e "${FILE}\t:${CURR}\t:${COUNT}"
done

cat > foo_call_count.h << EOF
#ifndef _FOO_CALL_COUNT_H
#define _FOO_CALL_COUNT_H

#define foo_call_count ${COUNT}

#endif /*_FOO_CALL_COUNT_H*/
EOF

Ну а дальше, делаете foo_call_count.h зависимым от всех с-файлов и генерируете его при помощи этого скрипта.

 

UPD. Улучшенная версия с предварительной обработкой препроцессором (препроцессор убирает комментарии).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо за совет, будем посмотреть

 

 

Не совсем понятно как формируется выражение

CURR=`cpp -E ${FILE} | grep -vv "^#" | grep "foo(" | grep -vv -c "void foo("`

Как я понял, последние два оператора проверяют синтаксис на наличие foo, но вот что делают первые два? :smile3046:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не совсем понятно как формируется выражение

CURR=`cpp -E ${FILE} | grep -vv "^#" | grep "foo(" | grep -vv -c "void foo("`

Как я понял, последние два оператора проверяют синтаксис на наличие foo, но не понятно что значит grep -vv , такое сочетание параметров я не нашел нигде. :smile3046:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Первый обрабатывает препроцессором файл, второй отбрасывает служебную инфу препроцессора (может не надо), 3 - выделяет все упоминания функции, 4 - исключает прототипы функции и подсчитывает оставшиеся.

Строчку "echo -e "${FILE}\t:${CURR}\t:${COUNT}"" можно удалить (исключительно для отладочных целей), ещё желательно натравливать препроцессор на файл с полным комплектом ключей компиляции.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо, прояснилось. Как я понимаю этот скрипт надо вписать в makefile?. И еще, давно хотел спросить, запись типа #define _FOO_CALL_COUNT_H определяет файл FOO_CALL_COUNT.H, но как препроцессор знает что перед H надо ставить точку. Почему просто не написать #include <FOO_CALL_COUNT.H>

 

:yeah:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

запись типа #define _FOO_CALL_COUNT_H определяет файл FOO_CALL_COUNT.H, но как препроцессор знает что перед H надо ставить точку.
Препроцессор ничего не знает и не ставит. Определяется символ _FOO_CALL_COUNT_H и дальше идет проверка именно этого символа. Это программист сам для себя решает, что _FOO_CALL_COUNT_H относится к файлу foo_call_count.h. Кстати, имена, начинающиеся с подчеркивания зарезервированы за компилятором и стандартной библиотекой, во избежание неприятностей свои имена с подчеркивания лучше не начинать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо, прояснилось. Как я понимаю этот скрипт надо вписать в makefile?. И еще, давно хотел спросить, запись типа #define _FOO_CALL_COUNT_H определяет файл FOO_CALL_COUNT.H, но как препроцессор знает что перед H надо ставить точку. Почему просто не написать #include <FOO_CALL_COUNT.H>

 

:yeah:

Скрипт лучше поместить в отдельный sh-файл и запускать при необходимости (из мейкфайла) (не уверен но может и из makefile-а работать).

Разберем конструкцию по строчкам:

1. #ifndef _FOO_CALL_COUNT_H

проверяем не объявлен ли _FOO_CALL_COUNT_H, если не объявлен - п.2. Если обьявлен - значит этот заголовочный файл включен не в первый раз и значит его содержимое можно не обрабатывать.

2. #define _FOO_CALL_COUNT_H

Это является стандартным обрамлением для заголовочных файлов.

Кстати, имена, начинающиеся с подчеркивания зарезервированы за компилятором и стандартной библиотекой, во избежание неприятностей свои имена с подчеркивания лучше не начинать.
Спасибо за замечание, учту.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Определяется символ _FOO_CALL_COUNT_H и дальше идет проверка именно этого символа. Это программист сам для себя решает, что _FOO_CALL_COUNT_H относится к файлу foo_call_count.h.

 

То есть, компилятор у себя в "уме" держит некую таблицу в которой, допустим, строке _FOO_CALL_COUNT_H соответствует include <FOO_CALL_COUNT.H>?

 

Скрипт лучше поместить в отдельный sh-файл и запускать при необходимости (из мейкфайла).

Разберем конструкцию по строчкам:

1. #ifndef _FOO_CALL_COUNT_H

проверяем не объявлен ли _FOO_CALL_COUNT_H.

Т.е запуск скрипта с помощью команды sh (скрипт)?

Хотел бы уточнить выражение (объявлен ли _FOO_CALL_COUNT_H), если следовать синтаксису С, то это запись (_FOO_CALL_COUNT_H FOO_CALL_COUNT.H ) или нет? Мне хотелось бы понять сам механизм.

 

:)

Изменено пользователем antiwin

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

То есть, компилятор у себя в "уме" держит некую таблицу в которой, допустим, строке _FOO_CALL_COUNT_H соответствует include <FOO_CALL_COUNT.H>?
Нет никакой таблицы. Нет никакого соответствия. вот смотрите:

foo.h:
#ifndef  FOO_H_INCLUDED__
#define FOO_H_INCLUDED__
.....
#endif  //FOO_H_INCLUDED__

abc.c:
#include "foo.h"
....
#include "foo.h"

Что происходит при компиляции abc.c?

1)удаляются все комментарии.

2)весь текст foo.h вставляется в те места, где был #include "foo.h". Все, #include исчезли, на их месте появился текст.

3) Теперь препроцессор проходит весь файл от начала до конца. В месте, где файл foo.h вставлен первый раз, он встречает строку #ifndef FOO_H_INCLUDED__.

4)Он ищет в своих списках символ FOO_H_INCLUDED__ и не находит его. Символ не определен. Условие выполнилось, препроцессор просматривает текст внутри условия.

5) тут он встречает строку #define FOO_H_INCLUDED__. Он вносит такой символ в свои списки - все, символ определен.

6) он просматривает файл дальше и доходит до места, где был второй #include "foo.h". Тут он снова встречает строку #ifndef FOO_H_INCLUDED__.

7) Он снова смотрит в своих списках и теперь уже находит там символ FOO_H_INCLUDED__. Условие не выполнилось, препроцессор выкидывает весь текст до #endif .

 

Все, содержимое foo.h попало компилятору только один раз. Как мы обозвали этот символ - FOO_H_INCLUDED__ или FOO_H_ или SKIP_THIS_FILE или TIPA_TEST - препроцессору все равно. Это наша забота, чтобы в каждом заголовочном файле был определен уникальный символ. И проще всего это сделать, связав имя символа с именем файла.

 

Чтобы понять смысл выражения "определен символ" - лучше всего прочитать документацию на препроцессор (не компилятор, а именно препроцессор - до компилятора эти символы не доходят).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это наша забота, чтобы в каждом заголовочном файле был определен уникальный символ...

Я правильно понал, об'явление уникального символа предохраняет от повторной компиляции?

А вроде бы у препроцессора есть функции на этот счет?

 

Он ищет в своих списках символ FOO_H_INCLUDED__ ...

Значит, что то вроде таблицы все та ки есть...

За ссылку спасибо, как почитаю отпишусь

немного отвлеченный вопрос.

AT (ADDR (.text) + SIZEOF (.text))

SIZEOF вроде понятно-это размер секции, тогда ADDR-это начало? и что это за оператор AT?.

И еще, в WinAvr есть папка с man, как вот эти man прочесть? Я думаю, что масса вопросов сразу бы отпала.

Изменено пользователем antiwin

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я правильно понал, об'явление уникального символа предохраняет от повторной компиляции?

А вроде бы у препроцессора есть функции на этот счет?

Есть, но они не стандартизованы (насколько я помню) и обладают рядом недостатков. Вот на этом форуме второй ответ описывает их. А обертка из #ifndef #define #endif работает везде. Вот неплохое описание
Значит, что то вроде таблицы все та ки есть...
Как это устроено внутри - не знаю, да это и не принципиально. Важно, что никаких таблиц соответствия имени символа и имени файла нет.
немного отвлеченный вопрос.

AT (ADDR (.text) + SIZEOF (.text))

Дежа-вю

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Привет всем, такой вот проблем: как можно узнать адрес в ОЗУ выше которого стек не "перерастет"? Это нужно сделать на этапе компиляции.

И еще, можно ли в теле функции узнать тип возвращаемого значения т.е допустим определена функция void *foo(...), далее где то вызывается int *ptr=foo(...), как в теле foo узнать что это указатель на int?

Изменено пользователем antiwin

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...