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

А как бы "феншуйно" использовать символы определяемые линкером?

Приветствую всех!

 

Исходные данные:

 

Компоновщику (gnu ld) задаем некоторый символ. Например:

-Xlinker --defsym -Xlinker __BUILD_DATE=0x$$(date +'%d%m%Y')

В итоге &__BUILD_DATE = 0x25042017, сегодня :)

 

В программе использование такой штуки тривиально, например:

extern void __BUILD_DATE;
..............
printf("Date: %X", (int)&__BUILD_DATE);

 

Теперь вопрос. Все работает давно, но согласно стандарту С конструкция написанная выше неправильная (ибо объект не может быть c типом void). Но в реальности по тому адресу ведь действительно ничего нет, т.е. в смысловом плане она соответствует реальности. Можно void заменить на uint8_t или что-то подобное, тогда конструкция будет правильная с точки зрения С, но неправильная в смысловом плане.

 

Хотелось бы узнать мнение у "знающих толк в извращениях" людей, как удовлетворить С и здравому смыслу :)

P.S. Один вариант знаю, через неполный тип, вот так:

extern struct _void_ __BUILD_DATE;

 

но с этим вариантом не будет работать расширение GCC известное, как арифметика указателей. Для приведенного выше примера это не важно, но в более изощренных случаях это существенно.

 

Короче хочется лаконичности и перфекционизма :), ну на крайний случай можно было бы просто отключить warning: taking address of expression of type 'void', но похоже он не отключаемый избирательно.

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

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


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

Можно так:

extern char __BUILD_DATE[];
..............
printf("Date: %p", __BUILD_DATE);

Со смысловым планом тут тоже не очень, но работать должно.

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


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

Всё не так. По феншую при сборке доп. утилита формирует хедер, в котором есть дата, ну а дальше как обычно.

А ещё есть __DATE__.

Кстати, "extern void foobar" - это забавно :biggrin:

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


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

Можно так:

extern char __BUILD_DATE[];
..............
printf("Date: %p", __BUILD_DATE);

Со смысловым планом тут тоже не очень, но работать должно.

Работает оно во всех случаях, но по смыслу самый подходящий вариант, который нарушает стандарт.

 

Всё не так. По феншую при сборке доп. утилита формирует хедер, в котором есть дата, ну а дальше как обычно.

Ну, а что делать с концом секции или с размером, которые определены в скрипте линкера? С точки зрения смысла они указывают в никуда, и для них extern void xxxx самое правильное определение.

 

А ещё есть __DATE__.

В данном случае мне нужна дата сборки, а __DATE__ даст дату компиляции файла к тому же в строковом представлении.

 

Короче одновременно красиво и по стандарту не выходит. Сделал макросы, чтобы компилятор не ругался, но выглядит это, как костыли...

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


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

__BUILD_DATE=0x$$(date +'%d%m%Y')

В итоге &__BUILD_DATE = 0x25042017

Феншуем не владею, более того ну вааще не понял синтаксиса и как из первой строки получается вторая, ну да ладно.

Все таки, чем __DATE__ не нравиться?

 

В данном случае мне нужна дата сборки, а __DATE__ даст дату компиляции файла к тому же в строковом представлении.

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

А строку в цифру можно перегнать макросами (не мое, тут на форуме как-то пробегало):

 

//==================================================================//
#ifndef _COMPILE_DATE_TIME_
#define _COMPILE_DATE_TIME_

#define COMPILE_HOUR   (((__TIME__[0]-'0')*10) + (__TIME__[1]-'0'))
#define COMPILE_MINUTE (((__TIME__[3]-'0')*10) + (__TIME__[4]-'0'))
#define COMPILE_SECOND (((__TIME__[6]-'0')*10) + (__TIME__[7]-'0'))

#define COMPILE_YEAR  ((((__DATE__[7]-'0')*10+(__DATE__[8]-'0'))*10+(__DATE__[9]-'0'))*10+(__DATE__[10]-'0'))

#define COMPILE_MONTH   ((__DATE__[2] == 'n' ? (__DATE__ [1] == 'a'? 0 : 5) \
                        : __DATE__[2] == 'b' ? 1 \
                        : __DATE__[2] == 'r' ? (__DATE__ [0] == 'M'? 2 : 3) \
                        : __DATE__[2] == 'y' ? 4 \
                        : __DATE__[2] == 'l' ? 6 \
                        : __DATE__[2] == 'g' ? 7 \
                        : __DATE__[2] == 'p' ? 8 \
                        : __DATE__[2] == 't' ? 9 \
                        : __DATE__[2] == 'v' ? 10 : 11)+1)

#define COMPILE_DAY  ((__DATE__[4]==' ' ? 0 : __DATE__[4]-'0')*10+(__DATE__[5]-'0'))
#endif
//==================================================================//

Результат такой же:

printf("%02u.%02u.%4u",COMPILE_DAY,COMPILE_MONTH,COMPILE_YEAR);

25.04.2017

 

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


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

Феншуем не владею, более того ну вааще не понял синтаксиса и как из первой строки получается вторая, ну да ладно.

Первая это кусочек из makefile, дата передается опцией компоновщику

 

Все таки, чем __DATE__ не нравиться?

Я ж вроде написал. Да и дата это только пример, в реальности много констант генерируются самим компоновщиком.

 

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

Дата+номер сборки дают однозначную информацию о версии. В принципе и номера сборки достаточно, но дата чаще нагляднее - глянул и сразу понятно. Впрочем номер сборки вводится таким же путем - по другому нельзя, т.к. иначе при изменении библиотек или ресурсов можно получить одинаковые номера сборок (номер генерируется автоматически через makefile).

 

А строку в цифру можно перегнать макросами (не мое, тут на форуме как-то пробегало):

Где-то наверное может быть полезным такой подход, но в данном случае это костыли. Вопрос то изначально был не столько о работоспособности (с чем проблем нет), а про красивый (лаконичный и отражающий смысл вкладываемый в него) код соответствующий стандартам С.

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


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

Ну, а что делать с концом секции или с размером, которые определены в скрипте линкера? С точки зрения смысла они указывают в никуда, и для них extern void xxxx самое правильное определение.

Про GCC не знаю, но в IAR конец секции можно так: завести некую переменную (в отдельной секции), а в скрипте линкёра указать расположить эту секцию последней в регионе размещения:

place in RAM_regionA {ro, first block IMAGE_HEAD, last section .codetail};

Насчёт переменных, определённых в скрипте линкёра можно так: положить их определения в отдельный *.h-файл и подключить этот файл к си-исходникам и к скрипту линкёра (линкёр IAR это позволяет).

А с датой (или вообще для общего случая произвольных символов) самое правильное имхо - как указал scifi. Я именно так и делаю.

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


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

jcxz, тут больше вопрос не в том, как можно - сам знаю не один способ. Вариант с определением символов компоновщика вполне устраивает, просто программа написанная наиболее близко по смыслу не вписывается в стандарт С (хотя GCC все компилирует нормально, немного поругавшись).

 

Вопрос скорее из серии перфекционизма :)

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


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

Вопрос скорее из серии перфекционизма :)

Я бы сказал, что из серии крайнего перфекционизма.

Мне бы не пришло в голову над такими вещами задумываться, хотя считаюсь педантичным человеком в глазах окружающих :)

 

Кстати, ИАР на такие конструкции смотрит благосклонно, не выдавая никаких варнингов:

 

ключ линкера

--define_symbol __BUILD_DATE=0x25042017

 

или строки скрипта линкера

define symbol __BUILD_DATE = 0x25042017;

export symbol __BUILD_DATE;

 

и в программе

extern void __BUILD_DATE;

...

printf("Date: %X", (int)&__BUILD_DATE);

 

Это потому, что в ИАР такие пользовательские символы линкера явно обрабатываются отдельно.

Компилятор же не позволит объявить неполный тип

void __BUILD_DATE;

А в случае пользовательского символа - пожалуйста, вот и нет предупреждений.

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


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

Вариант с определением символов компоновщика вполне устраивает, просто программа написанная наиболее близко по смыслу не вписывается в стандарт С (хотя GCC все компилирует нормально, немного поругавшись).

Хочу поставить ЖЫРНУЮ точку.

Значит, пользуемся фичей GCC, а именно определение символа с датой средствами компоновщика. Опять же, в GCC всё работает. Так что ещё тебе надо, любезный? Стандарт Си тут совсем сбоку, поскольку изначально речь идёт о GCC. В других средах другие дела. Короче, дело надо закрыть, так как нет состава преступления. За сим откланяюсь, Ваша Честь.

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


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

вот и нет предупреждений.

В GCC более ранних версий предупреждений тоже не было, возможно у IAR все еще впереди :)

 

Так что ещё тебе надо, любезный?

Чтобы компилятор не ругался :)

 

В реальности он у меня сейчас не ругается, но коряво это выглядит в коде, а когда красиво ругается.

 

Стандарт Си тут совсем сбоку, поскольку изначально речь идёт о GCC.

Нет. Он из-за стандарта ругается, ибо конструкция не по стандарту.

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


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

Нет. Он из-за стандарта ругается, ибо конструкция не по стандарту.

Тут уж надо определиться. Или по стандарту - и тогда никакой линкерной магии. Или с магией - но тогда не по стандарту.

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


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

Или по стандарту - и тогда никакой линкерной магии. Или с магией - но тогда не по стандарту.

Ну да, или с магией, по стандарту, но с кривой программой. Нет гармонии :)

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


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

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

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

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

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

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

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

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

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

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