написал генератор псевдо-случайных чисел времени компиляции на основе рекурсивных шаблонов... в качестве зерна для рандомизатора хотел использовать время и дату компиляции, то есть символы в переменной препроцессора например: (__TIME__[0] - '0') и другие... но получаю ошибку о том, что элементы массива не могут быть использованы в константных выражениях... подскажите, как заставить препроцессор взять значение __TIME__[0], а не делать тупую символьную подстановку, и вообще возможно ли это? может быть есть какие-то альтернативы, которые я мог бы использовать в качестве зерна рандомизатора? чтобы было понятнее, приведу пример кода: Код (Text): // Пример определения генератора #define COMPILETIME_RANDSEED (__TIME__[0] - '0') template <uint32_t N> struct CompileTime_Random { enum { Value = 100 + CompileTime_Random<N - 1>::Value }; }; template <> struct CompileTime_Random<0> { enum { Value = COMPILETIME_RANDSEED }; }; #define COMPILETIME_RANDOM CompileTime_Random<__COUNTER__>::Value // Пример использования printf("%d\n", COMPILETIME_RANDOM); printf("%d\n", COMPILETIME_RANDOM); printf("%d\n", COMPILETIME_RANDOM); ЗЫ необходимо решить средствами стандартного препроцессора ЗЗЫ будем внимательны, обсуждаем генератор псевдо-случайных чисел времени компиляции ЗЗЗЫ понятно, что всегда можно устанавливать зерно руками, но очень не хотелось бы этого делать, тк генерировать зерно относительно времени компиляции гораздо красивее и удобнее...
я пробовал... в этом случае возвращается ошибка мол COMPILETIME_RANDSEED не может присутствовать в константном выражении... если задать COMPILETIME_RANDSEED каким-то константным значением, то все проходит на ура... хитрый компилятор мать его)
А если двойную макроподстановку попробовать? Код (Text): #define __GEN_COMPILETIME_RANDSEED (__TIME__[0] - '0') #define COMPILETIME_RANDSEED __GEN_COMPILETIME_RANDSEED
Можно также сделать утилиту, которая генерирует в run-time вот такой файл: Код (Text): #define COMPILETIME_RANDSEED <random value here> и затем перед каждой компиляцией запускать утилиту - в BAT пакете или там в Pre-Build Step - если через среду.
ты уверен, что проделал именно тот самый тест)) например: Код (Text): const int Test1 = __TIME__[0]; enum Test2 { value = Test1 }; мингв отвечает: я пробовал, проблема в том, что препроцессор не хочет вычислять значение, а делает тупую текстовую подстановку: Код (Text): #define __GEN_COMPILETIME_RANDSEED (__TIME__[0] - '0') #define COMPILETIME_RANDSEED __GEN_COMPILETIME_RANDSEED enum Test2 { value = COMPILETIME_RANDSEED }; мингв отвечает: да это понятно... я хотел бы обойтись стандартными средствами... с тем же успехом можно свой препроцессор написать... кстати я никогда не пробовал прикручивать сторонние препроцессоры... как это сделать? я могу поставить его в пребилд-ивент, но куда генерировать файлы после обработки и как сделать чтобы затем их подцеплял компилятор? какие готовые препроцессоры существуют для плюсов? я только GPP знаю...
да... но это на чисто на препроцессоре, там не сделаешь добротного алгоритма генерации псевдо-случайных чисел... это случайное число фактически генерируется не препроцессором, а оптимизатором компилятора... препроцессор только подставляет строку в код... для моего случая твоя идея похоже тоже не подходит, тк в константных выражениях не могут присутствовать касты типов и указатели сами по себе... никогда не пробовал comeau, хороший компилятор? как у него с поддержкой C++0x? и он платный вроде, не?
Rel га? вы не поняли, но уже против? окончание ответа, начиная с подставления строки в код непонятно уже мне. пользоваться или нет - дело ваше. код дает константные случайные числа от 0 и до 63 разрядов. -- (char)127 -- константа (void*)0 -- тоже константа // int foo(){printf("foo");} &foo -- тоже как ни странно константа (unsigned)&foo + 8 -- снова константа и в компиляте вы увидите ее как одно число не бойтесь С, он почти не кусается.
Rel Вообще-то шаблоны это то-же препроцессор, но слегка улучшенный. Так что qqwe прав, данную задачу вполне можно решить препроцессором. Но сдаётся мне что проблема с __TIME__, это какое-то надуманное ограничение компилятора для перечислений. Ничто не мешает использовать функции, главное хорошенько заинлайнить. Отличный, платный. С C++0x как и у всех, то-есть частично.
дело не в си... я вряд ли смогу использовать ваше решение так как мне нужно... попробую уточнить... например, как вашим методом сделать так: Код (Text): printf("%d\n", RND_N); // Одно число printf("%d\n", RND_N); // Другое число printf("%d\n", RND_N); // Третье число макрос должен как-то себя менять... или например, есть определенное количество инлайн-функций, как подставить в код случайную из них: Код (Text): #define RND_FUNC(prefix, maxid) prefix_##(RND_N % (maxid + 1)) не сработает, так как оператор ## исполняется раньше подстановки... я как бы ничего не имею против вашего решения, просто видимо для моей задачи оно не применимо... задачу решил с помощью нового стандарт C++0x и constexpr... для этого правда пришлось прокачать свою MinGW до GCC версии 4.6.0... но зато сейчас решение красивое и работает) спасибо всем за помощь, если есть еще идеи по теме или просто по вычислениям во время компиляции, с удовольствием их пообсуждаю с вами)
Rel не знаю, это зависит от фантазии. например, так Код (Text): #define SEED 11 #define RND_N(n) ((*(long long*)__TIME__ + ((n) << 16))% (long long)SEED) но вы, наверно, понимаете, что тк источник случайности 1, то такие числа будут псевдослучайными. трудно ответить, тк я не вполне понимаю чего вы этим хотите добиться. вообще не понимаю. например, < % (maxid + 1) > это возможная, но неправильная форма. делитель определяет только разрядность и разброс остатка. наилучший разброс дают простые делители, те делить надо на фиксированное, достаточно большое простое число. как решать вашу задачу - дело ваше. вам красиво, значит вам красиво. я же люблю универсальность и простоту.
ну можно взять простой алгоритм из ANSI-C: Код (Text): randhold = 12345 + 1103515245 * randhold; return randhold; подскажите, как его переписать для генерации псевдослучайных чисел во время компиляции с помощью препроцессором? ну как объяснить... есть (maxid + 1) инлайн функций, допустим они имеют вид prefix_id (например func_0, func_1, ..., func_maxid)... необходимо в определенные места обычных функций подставить код случайно выбранной инлайн функции... этакий "морфинг" кода при компиляции... такими инлайн функциями могут быть допустим различные антиотладочные приемы, или какой-то хитрый асм-код делающий что-нибудь полезное или же бесполезное, смущая человека производящего анализ кода... и от компиляции к компиляции такие вставки будут различны...
Rel я вот не пойму, чем вам так въелись эти псевдослучайные числа, если у вас есть настоящие случайные - дата и время компиляции + текущая строка вставки макроса? будьте проще. например, Код (Text): #define RND_N (unsigned)(((*(long long*)__TIME__ + ((long long)*(long*)&__TIME__[4] << 31)) ^ ((long long)__LINE__ << 21)) % (long long)SEED) и в каждой строке иное случайное число (единственно что, __TIME__ имеет шаг > 1 сек) для таких целей немного неверно использовать инлайн функции. компилятор по своему усмотрению (вызовы из нескольких мест, слишком много кода (как вы будете сбивать с толку малым количеством простого кода?)) может скомпилировать инлайн функцию отдельно. толку тогда от такой "антиотладки"? в данном случае, надежнее использовать настоящий макрос. а случайность добавить с помощью свитча или серии ифов от этой случайной константы. Код (Text): #define KURDY_BURDY \ switch(RND_N){ \ case 1: \ printf("1\n"); \ break; \ \ case 2: \ printf("2\n"); \ break; \ \ // .... \ \ default: \ printf("default\n"); \ break; \ \ } ьщжете попробовать повставлять в разных строках RND_N или KURDY_BURDY
__COUNTER__ макрос подойдет, но он только c VS 10 вроде-бы... Код (Text): #include <stdio.h> #define FUNC2(x,y) x##y #define FUNC1(x,y) FUNC2(x,y) #define FUNC(x) FUNC1(x,__COUNTER__) int FUNC(my_unique_prefix); int FUNC(my_unique_prefix); int main() { my_unique_prefix0 = 0; printf_s("\n%d",my_unique_prefix0); my_unique_prefix0++; printf_s("\n%d",my_unique_prefix0); }
каунтер макрос доступен в гцц с версии 4.3: http://gcc.gnu.org/gcc-4.3/changes.html как его ограничить модулем? пример: Код (Text): #define FUNC2(x,y) x##y #define FUNC1(x,y) FUNC2(x,y) #define FUNC(x) FUNC1(x,__COUNTER__ [b]% 4[/b] ) inline void func0() { printf("FUNC 0!\n"); } inline void func1() { printf("FUNC 1!\n"); } inline void func2() { printf("FUNC 2!\n"); } inline void func3() { printf("FUNC 3!\n"); } int main() { FUNC(func)(); FUNC(func)(); FUNC(func)(); FUNC(func)(); FUNC(func)(); return 0; } __TIME__ - время начала компиляции, оно не меняется во время компиляции... да это понятно... тем более, что __forceinline вроде не поддерживается в гцц, надо проверить... тут надо хорошо знать компилятор, чтобы инлайны действительно стали инлайнами... макросы скорее всего не подходят, так как инлайн функции в основном написаны на ассемблере и собираются другим компилятором... да, идея со свитчем/ифами мне нравится...