Константы (const) не могут служить границами масс

 
0
 
C++
ava
Andrey Bushman | 16.03.2013, 22:12
Доброго времени суток.

Насколько я понял из прочтённого в литературе по C - размер массивов должен назначаться константным значением, т.е. это может быть либо целочисленная переменная, объявленная через #define, либо целочисленная переменная, объявленная как const, либо значение из enum, или же, как последний вариант - непосредственно указывается число.

Сейчас я прочитал такую информацию:
Цитата (Брайан Керниган)


Определяйте числа как переменные-константы, а не как макросы.

...

В языке C тоже есть ключевое слово const, но такие константы не могут служить границами массивов, поэтому в C следует отдавать предпочтение перечислимому типу (enum).

...



Полагаю, что под "границей" массива подразумевается его размер. Я не понял, почему константы не могут служить границами массивов?
Следующий код успешно компилируется, хотя границы массива создаются как на основе константы, так и на основе enum-значения:

/*
cd ~
gcc ./test.c -o ./test.out -std=c90
./test.out
*/
#include<stdio.h>

const int max = 100;

enum {
    Min = 0,
    Max = 100
};

int main(void) {
    char s[max]; /* Размер массива - константа */
    s[0] = '\0';
    
    char t[Max]; /* Размер массива - перечисление */
    t[0] = '\0';
        
    return 0;
}


Скорее всего, я что-то не верно понял... Тогда что именно?

С уважением, Андрей
Comments (17)
ava
Alexeis | 16.03.2013, 23:03 #
Никаких ошибок нет.

http://liveworkspace.org/code/2YpCHc$0
ava
Andrey Bushman | 16.03.2013, 23:06 #
Цитата (Alexeis @ 16.3.2013,  23:03)
Никаких ошибок нет.



http://liveworkspace.org/code/2YpCHc$0

А разве я писал, что есть ошибка?
ava
volatile | 16.03.2013, 23:34 #
Цитата (Compositum @  16.3.2013,  21:12 findReferencedText)
в литературе по C - размер массивов должен назначаться константным значением

Compositum, во первых, для современного С это уже не так, там можно вообще объявлять размеры не константными переменными.

В С++ нужны константы, но константы бывают разные.
1. константы времени компиляции
2. константы времени исполнения.
так вот, размеры массивов можно задавать только первыми.
ava
feodorv | 16.03.2013, 23:36 #
Цитата (Compositum @  16.3.2013,  22:12 findReferencedText)
почему константы не могут служить границами массивов?

Потому что ключевое слово const в C означает лишь запрет на модификацию значения переменной, а отнюдь не константу компиляции:

int throughPrecision( const int precision )
{
  double values[precision];
  ...
}

Здесь при вызове throughPrecision (но не в теле функции) всё едино, что precision - константа, что не константа:

#define MAX_PRECISION 10
...
int retval = throughPrecision( MAX_PRECISION );
int retval2 = throughPrecision( retval );


Долгое время можно было задавать размеры массивов только как константу компиляции, но со времён C99 появилась поддержка массивов переменной длины. Видимо, Вы читаете те советы Кернигана, которые не учитывают эти нововведения (их ещё просто не было на момент написания этих советов). А компилируете уже современным компилятором)))
ava
Andrey Bushman | 17.03.2013, 08:32 #
Цитата


Compositum, во первых, для современного С это уже не так, там можно вообще объявлять размеры не константными переменными.



В С++ нужны константы, но константы бывают разные.

1. константы времени компиляции

2. константы времени исполнения.

так вот, размеры массивов можно задавать только первыми.


Меня интересует именно C90, поскольку этот стандарт полностью поддерживается современными компиляторами, в отличие от стандартов C99 и C11.
Цитата


Долгое время можно было задавать размеры массивов только как константу компиляции, но со времён C99 появилась поддержка массивов переменной длины. Видимо, Вы читаете те советы Кернигана, которые не учитывают эти нововведения (их ещё просто не было на момент написания этих советов). А компилируете уже современным компилятором)))


Я понимаю, что современные компиляторы могут больше, чем требует стандарт, но ведь я при компиляции указал опцию -std=c90, которая, как я понимаю, должна следить за тем, чтобы код полностью соответствовал указанному стандарту и не содержал в себе ничего кроме этого. Компиляция ведь с обозначенной опцией проходит успешно... А может быть это ошибка в русском переводе? 
ava
Andrey Bushman | 17.03.2013, 09:09 #
Обратите внимание на следующий код:

/*
cd ~
gcc ./test.c -o ./test.out -std=c90
./test.out
*/
#include<stdio.h>

const int max = 100;

enum {
    Min = 0,
    Max = 100
};

int f(){
    return 100;
}

int main(void) {
    char s[max]; /* Размер массива - константа */
    s[0] = '\0';
    
    char t[Max]; /* Размер массива - перечисление */
    t[0] = '\0';    
    
    const int x = f();
    char n[x]; /* Размер массива - константа, значение которой получено в
    результате вычисления некоторой функции. */
    n[0] = '\0';
    
    /* WARNING: Здесь ожидал получить ошибку компиляции: */    
    char m[f()]; /* Размер массива - значение функции */
    m[0] = '\0';
        
    return 0;
}


В этом коде я назначаю константе x вычисляемое значение. В C# такой фокус бы не прошёл, но в C#, при компиляции в CIL, насколько я помню, в исходном коде все const переменные заменяются их значениями.

Затем для массива m я в качестве размера подставляю функцию, а не константное значение. Ожидаю, что в этом месте получу ошибку компиляции (особенно с учётом того, что при компиляции указана опция -std=c90), однако код компилируется без проблем.

Честно говоря, я в замешательстве...
ava
Alexeis | 17.03.2013, 12:08 #
Может компилятор слишком умный и оптимизирует функцию до инлайна. Хотя синтаксис все равно должен проверять. Возможно ключ std=c90 работает не совсем так как вы предполагаете. Компилятор VS2010 ?
ava
Andrey Bushman | 17.03.2013, 12:18 #
Цитата (Alexeis @ 17.3.2013,  12:08)
Может компилятор слишком умный и оптимизирует функцию до инлайна. Хотя синтаксис все равно должен проверять. Возможно ключ std=c90 работает не совсем так как вы предполагаете. Компилятор VS2010 ?

В самом начале приведённых мною исходников находится комментарий, согласно которому видно, что используется язык C (это на всякий случай упоминалось и в первом сообщении темы), следовательно ни о каких "инлайнах" речи быть не может, операционная система так же очевидна из того же комментария - Linux (соответственно это не может быть MS VS), и компилятор указан: gcc.
ava
feodorv | 17.03.2013, 13:34 #
Цитата (Compositum @  17.3.2013,  09:32 findReferencedText)
Компиляция ведь с обозначенной опцией проходит успешно... 

Даже предупреждений не выдаёт???
ava
Фантом | 17.03.2013, 13:40 #
Цитата (Compositum @  17.3.2013,  13:18 findReferencedText)


В самом начале приведённых мною исходников находится комментарий, согласно которому видно, что используется язык C (это на всякий случай упоминалось и в первом сообщении темы), следовательно ни о каких "инлайнах" речи быть не может,


В C99 они есть.  smile 

Что касается ситуации в целом, то тут все просто. Если посмотреть man gcc, то там обнаружится следующий текст (выделение мое):
Цитата


c90

c89

iso9899:1990
       Support all ISO C90 programs (certain GNU extensions that
       conflict with ISO C90 are disabled). Same as -ansi for C code.


Из него следует, что gcc в таком случае отключает не все расширения, не соответствующие стандарту ANSI C, а только те, которые конфликтуют со стандартом. Неконстантные размеры массива - это одно из расширений GCC (затем перекочевавшее в C99), которое ни с чем не конфликтует, поэтому оно включается в любом случае.

Для того, чтобы при компиляции получить точное соответствие желаемому стандарту, необходимо, в дополнение к указанию -std, поставить ключ -pedantic, тогда Вы получите желаемое.

P.S. Но, честно говоря, вот это утверждение:
Цитата (Compositum @  17.3.2013,  09:32 findReferencedText)


Меня интересует именно C90, поскольку этот стандарт полностью поддерживается современными компиляторами, в отличие от стандартов C99 и C11.

на мой взгляд, достаточно странно. Насчет C11 спорить не буду, это действительно так, а вот более-менее современный компилятор, не поддерживающий C99 - это уже нечто странное. Пожалуй, в современных условиях об ANSI C уже можно совершенно спокойно забыть, благо что C99 по многим причинам существенно лучше.
ava
xvr | 18.03.2013, 13:28 #
Цитата (Compositum @  17.3.2013,  09:09 findReferencedText)
Обратите внимание на следующий код:

Действительно. Этот код должен был сломаться в C90 (pedantic) режиме даже не доходя до констант -


int main(void) {
    char s[max]; /* Размер массива - константа */
    s[0] = '\0';
    
    char t[Max]; /* Размер массива - перечисление */
    t[0] = '\0';    

Объявление переменных в С90 было возможно только в начале блока, но никак не после первой же исполняемой конструкции. Т.е. на char t[Max]; уже должно было сломаться
ava
Andrey Bushman | 18.03.2013, 14:06 #
 Проблема была в том, что изначально я указывал компилятору недостаточно опций и проверка на соответствие стандарту C90 проходила не столь педантично, как мне было нужно. Если выставить все нужные опции, то const действительно нельзя будет использовать (это ограничение закреплено в стандарте):

cd ~/test
gcc ./test.c -o ./test.out -ansi -pedantic-errors
gcc ./test.c -o ./test2.out -std=c90 -pedantic-errors
gcc ./test.c -o ./test3.out -std=iso9899:1990 -pedantic-errors
./test.out

Цитата


более-менее современный компилятор, не поддерживающий C99 - это уже нечто странное.


А что, уже появились компиляторы, которые на 100% поддерживают C99 (если не считать Sun Studio)? Насколько мне известно, их нет и даже более того - они не планируются, т.к. составлен C99 был плохо и одной из задач  C11 было устранение "неровностей" C99 и перевод ряда требований в разряд всего лишь "рекомендуемых" (т.е. не обязательных). Вместо C99 разработчики компиляторов сосредоточились на C11.

Например gcc до сих пор так и не поддерживает C99 на 100%, а MS Visual Studio его ВООБЩЕ не поддерживает, заявляя, что всем разработчикам следует переходить с C на C++.
ava
Фантом | 18.03.2013, 15:41 #
Цитата (Compositum @  18.3.2013,  15:06 findReferencedText)


А что, уже появились компиляторы, которые на 100% поддерживают C99 (если не считать Sun Studio)?


А Вы из принципа хотите пользоваться ими только при 100%-ой поддержке? Есть определенное подмножество нововведений, которые включены практически во все компиляторы, ими и стоит пользоваться.

Цитата (Compositum @  18.3.2013,  15:06 findReferencedText)
MS Visual Studio его ВООБЩЕ не поддерживает, заявляя, что всем разработчикам следует переходить с C на C++. 

Я бы сказал, что всем разработчикам следует переходить с MSVS на нормальные компиляторы.  smile 
ava
Andrey Bushman | 18.03.2013, 17:19 #
Цитата


А Вы из принципа хотите пользоваться ими только при 100%-ой поддержке? Есть определенное подмножество нововведений, которые включены практически во все компиляторы, ими и стоит пользоваться.


Не нужно обижаться на меня и искать подвох в мои вопросах -  я не с этой целью их задавал. Не так давно я искал компиляторы, которые бы полностью соответствовали  C99 или C11, но безуспешно. Если за это время что-то появилось, то я с интересом отнесусь к этому. Я стараюсь быть практиком (возможно несколько боязливым). Для меня важно, чтобы я мог свой код компилировать под разные платформы без изменеий. Соответствие стандартам  это, своего рода, некоторый гарант такой возможности. А если одни стандарты будут поддерживать лишь часть С99 или С11, а другие будут поддерживать другую часть С99 или С11, то велика вероятность того, что воникнут такие места, которые поддерживаются не обоими сразу, в следствии чего мне придётся править код директивами препроцессора, чего я очень не хочу. В Windows наиболее популярный компилятор - это cl.exe, а в Linux - это gcc. Именно из этих соображений в Windows я пользуюсь cl.exe (компилятор Visual Studio), а в Linux - gcc. Ну и ещё потому, что в Windows я часто пишу на C#.

ava
sQu1rr | 18.03.2013, 17:36 #
Цитата (Compositum @  18.3.2013,  17:19 findReferencedText)
Не так давно я искал компиляторы, которые бы полностью соответствовали  C99 или C11, но безуспешно

http://en.wikipedia.org/wiki/C99 - как минимум 5 компиляторов поддерживают С99 полностью
ava
feodorv | 18.03.2013, 17:42 #
Цитата (Compositum @  18.3.2013,  18:19 findReferencedText)
Не нужно обижаться на меня и искать подвох в мои вопросах

Ваши вопросы вызывают недоумение, причём здесь обида и подвох.
Разница в применяемом API и инструментарии между Windows и Linux будет создавать на порядок больше проблем, чем несоответствие новым стандартам. Если не хотите здесь никаких неожиданностей, пишите на ANSI С, никто же заставляет Вас насильно использовать нововведения. Более того, возможно, Вам больше подойдёт платформонезависимый инструментарий и язык C++...
ava
Фантом | 18.03.2013, 21:13 #
Цитата (Compositum @  18.3.2013,  18:19 findReferencedText)


Не нужно обижаться на меня и искать подвох в мои вопросах -  я не с этой целью их задавал.

Упаси боже. Я совершенно честно не могу понять Вашу мотивацию.

Цитата (Compositum @  18.3.2013,  18:19 findReferencedText)
Для меня важно, чтобы я мог свой код компилировать под разные платформы без изменеий. Соответствие стандартам  это, своего рода, некоторый гарант такой возможности.

Кроссплатформенность - это действительно хорошо. Но вот привязка ради нее именно к стандарту... C, по уже сложившейся традиции, не тот язык, в котором принято тщательно относиться с соблюдению стандартов, поэтому этим требованием Вы себя сильно ограничиваете. При этом смысл такого ограничения действительно неясен: есть доступный практически везде GCC (он же MinGW), есть два-три честно соответствующих стандарту компилятора (например, уже упомянутый SUN'овский и PGI). Но зачем пользоваться наиболее популярными под данной платформой компиляторами?
Please register or login to write.
Firm of day
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Contributors
advanced
Submit