LINUX.ORG.RU

Определение размерности массива в «рантайме» в gcc

 ,


0

2

Всё время считал, что размерность массива должна быть определена на этапе компиляции. Поэтому, данный код, по идее, должен быть не валидным:

#include "stdio.h"

int foo(int x) {
	return x + 5;
}

int bar() {
	return 3;
}


int main(int argc, char const *argv[]) {
	
	int x[foo(3)];
	printf("%zu\n", sizeof(x));

	int y = foo(3);
	int ya[y];
	printf("%zu\n", sizeof(ya));

	int z = 3;
	int zz = foo(z);
	int za[zz];
	printf("%zu\n", sizeof(za));

	int a[foo(bar())];
	printf("%zu\n", sizeof(a));
	
	return 0;
}
Но GCC компилирует, и даже не кидает ворнингов с -Wall. Пробовал компилить с -ansi, -std=iso9899:199409, -std=gnu90, также отключал инлайнинг (-fno-default-inline) и вообще всю оптимизацию (-O0) - результат один и тот же - всё компилится без предупреждений и даже запускается.

Что поэтому поводу говорит стандарт? Когда так делать можно, а когда нельзя?



Последнее исправление: cetjs2 (всего исправлений: 1)
Ответ на: комментарий от WRG

Фактически да, т.к. entry point распологается по адрессу 0x0000 — т.е. просто запускается всё заново.

PS: это такой long_jump(0) получается.

beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 1)

Когда так делать можно, а когда нельзя?

Начнём с того, что функция возвращает int вместо unsigned int. Уже только за это компилятор должен выплюнуть ошибку. Но... этого не сделали по разумным причинам, функция может быть сложной, корректный результат выплевывать только из под root и т.п.

Имхо, делай функции с проверками, если нужно считать в рантайме. Или используй константы во время компиляции.

gh0stwizard ★★★★★
()
Ответ на: комментарий от post-factum

Понятно, что c++11, но я не знаю другого способа организации compile time вычислений. Ну шаманство с макросами ещё, ок

Anvill
() автор топика
Ответ на: комментарий от WRG

Только если память кода с нулевого адреса начинается. У STM32, например, этот финт не прокатит. И да, стек и регистры ведь будут засраты. Да и железо с прерываниями уже инициализировано. Фиговый способ рестарта.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Anvill

в plain С через enum простые вычисления на выражениях вроде можно

enum
{
kElementSize = sizeof(int),
kElementCount = 134,
kArraySize = kElementSize * kElementCount
};

Но не знаю насколько это стандартно

GPFault ★★
()
Ответ на: комментарий от GPFault

Не уверен, что кому-то понравиться смотреть на такой код

Anvill
() автор топика
Ответ на: комментарий от Eddy_Em

А ты забавный, написал код, поведение которого зависит от погоды на марсе, ну и немножко от random seed, и ждёшь что оно будет падать у всех :)

pon4ik ★★★★★
()
Ответ на: комментарий от Eddy_Em

Да кстати мэй би и стабильно, надо допетрить, как зерно срабатывает ибо :

If no seed value is provided, the rand() function is automatically seeded with a value of 1.

Но по идее от системы к системе, и состоянию памяти к состоянию памяти, должна таки наибольшую роль играть случай, хм.

Интересно, может кто разьяснит, на скорую руку?

Ну, по большому счёту всё зависит от реализации libc, если чиселки там захардкоженны, то будет штабильненько выдавать, если беруться из памяти, то в дебажной сборке будет более менее стабильно падать видимо.

pon4ik ★★★★★
()
Последнее исправление: pon4ik (всего исправлений: 1)
Ответ на: комментарий от post-factum

Сорцы это наше всё, но мне страшно лень:)

Если ты разобрался, то скажи как на духу - захардкоженны там чиселки с которыми база складывается и перемножается или откуда то есчё они беруться?

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

Захардкожены. И это мой косяк. Надо было хотя бы srand(time(NULL)) сделать. А вообще, у меня обычно инициализатор через /dev/random.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Ну если захардкоженны - то падать должно в зависимости от версии libc максимум?

Или я чего то недогоняю? Если циферка в качестве зерна туда передаётся всегда 1 по умолчанию, и остальные составляющие формулы - захардкоженны, то выходит оно должно всегда выдавать одно и то же число, как минимум на одной и той же версии libc?

pon4ik ★★★★★
()
Ответ на: комментарий от Eddy_Em

у меня обычно

Интересно, что за область, если надо часто srand юзать - чисто любопытно :)

Я вот для чего то умного ни разу не использовал рандомные чиселки.

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

надо какойнибудь емоций поставить?

Нет, надо выйти из каменного века и поставить шрифты которые поддерживают что-то, что имеет коды выше ASCII

sambist ★★
()
Ответ на: комментарий от Anvill

Плюсую. До сих пор не могу читать GAS, а intel flavor норм.

anonymous
()
Ответ на: комментарий от Anvill

А что тут не так? Первое (и, в вашем примере единственное) возвращаемое функцией foo значение, впринцыпе, всегда одинаково и известно на момент компиляции.

RiseOfDeath ★★★★
()
Ответ на: комментарий от pon4ik

Выходит, что так. ХЗ. Не копал.

Интересно, что за область, если надо часто srand юзать - чисто любопытно :)

Матмодели всякие разные. И нужно как можно более "натуральным" ГСЧ сделать. Я drand48() использую с периодическим srand48().

Да я код инициализатора приводил:

/**
 * function for different purposes that need to know time intervals
 * @return double value: time in seconds
 */
double dtime(){
    double t;
    struct timeval tv;
    gettimeofday(&tv, NULL);
    t = tv.tv_sec + ((double)tv.tv_usec)/1e6;
    return t;
}
/*
 * Generate a quasy-random number to initialize PRNG
 * name: throw_random_seed
 * @return value for srand48
 */
long throw_random_seed(){
    long r_ini;
    int fail = 0;
    int fd = open("/dev/random", O_RDONLY);
    do{
        if(-1 == fd){
            perror(_("Can't open /dev/random"));
            fail = 1; break;
        }
        if(sizeof(long) != read(fd, &r_ini, sizeof(long))){
            perror(_("Can't read /dev/random"));
            fail = 1;
        }
        close(fd);
    }while(0);
    if(fail){
        double tt = dtime() * 1e6;
        double mx = (double)LONG_MAX;
        r_ini = (long)(tt - mx * floor(tt/mx));
    }
    return (r_ini);
}
А потом в нужных местах:

srand48(throw_random_seed());
Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от RiseOfDeath

Я тоже, честно говоря, не понял, где «криминал» в коде ТС.

Twissel ★★★★★
()
Ответ на: комментарий от post-factum

Половинку. Ну если статья правдива, то на кой же черт таки нужен random?

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от post-factum

Дочитал, дошло. Действительно, в данном случае (да и подавляющем большинстве моих велосипедов) нафиг не нужен /dev/random, можно и /dev/urandom обойтись.

Однако, т.к. я всего-то беру одно long число для инициализации, то пофиг: уж на него-то "энтропия" всегда есть, и ждать, пока новая накопится, не придется.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от pon4ik

Да практически любые попробуйте, например, DeJa Vu или Ubuntu.

sambist ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.