powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Константы (const) не могут служить границами массивов в C?
25 сообщений из 27, страница 1 из 2
Константы (const) не могут служить границами массивов в C?
    #38186935
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Доброго времени суток.

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

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

Полагаю, что под "границей" массива подразумевается его размер. Я не понял, почему константы не могут служить границами массивов?
Следующий код успешно компилируется, хотя границы массива создаются как на основе константы, так и на основе enum-значения:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
/*
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;
}


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

С уважением, Андрей
__________________
Британские "учёные" - фундаментальный подход к разной фигне...
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38186964
petrav
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumСкорее всего, я что-то не верно понял... Тогда что именно?
А Вы чем занимаетесь? Случайно не учите ли Вы С++ начиная с С?

В книгах могут быть ошибки. Но Кернигана мы все знаем и чтим.

Суть вещей очень проста. Размер массива должен быть однозначно определен в момент компиляции приложения. Т.е. это такие варианты: константа, enum (перечисление), define, число (литерал). Правильный вариант только один: константа (но есть исключения).

Gcc и WinAPI позволяют создавать локальные массивы заранее неизвестной длинны. Но это никчемный путь.
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38186978
petrav Суть вещей очень проста. Размер массива должен быть однозначно определен в момент компиляции приложения. Т.е. это такие варианты: константа, enum (перечисление), define, число (литерал). Правильный вариант только один: константа (но есть исключения).
А чем enum то не угодил?
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38186979
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
petravА Вы чем занимаетесь? Случайно не учите ли Вы С++ начиная с С?
Нет, я именно C и учу (ISO/IEC 9899:1990, если быть более точным). K&R уже прочитал, попутно выполняю упражнения из книги. Сейчас читаю книгу "Практика программирования", написанную указанным мною выше автором.

petravСуть вещей очень проста. Размер массива должен быть однозначно определен в момент компиляции приложения.

Это я знаю.
petravТ.е. это такие варианты: константа, enum (перечисление), define, число (литерал).

Это я тоже знаю, но выше указанная мною цитата сбивает с толку...
petravПравильный вариант только один: константа (но есть исключения).

Понимаю это, но опять же - какая-то несостыковка с указанным мною выше текстом...

petravGcc и WinAPI позволяют создавать локальные массивы заранее неизвестной длинны. Но это никчемный путь.

При компиляции я указываю опцию -std=c90, сообщая тем самым, что исходный код следует проверять на полное соответствие стандарту C90 (т.е. ISO/IEC 9899:1990). В соответствии с указанным мною стандартом размер массива должен задаваться константой (в C11 размер можно назначать динамически, но не в C90). Поскольку меня интересует написание кода в соответствии со стандартом, то дополнительные возможности от Gcc и WinAPI пока игнорирую.

@ petrav
Вы мне вроде и написали, но... Ответа на мой вопрос в вашем сообщении не содержится. :)
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38186987
petrav
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
enum не угодил?petrav Суть вещей очень проста. Размер массива должен быть однозначно определен в момент компиляции приложения. Т.е. это такие варианты: константа, enum (перечисление), define, число (литерал). Правильный вариант только один: константа (но есть исключения).
А чем enum то не угодил?
Можно купить мерседес (черный!:) и поехать на нем траву косить.

Каждой вещи свое назначение. Использование перечислений по не прямой надобности родилось тогда, когда в стандарте не было такого:
Код: plaintext
1.
2.
3.
4.
class foo
{
    static std::size_t const Max = 128;
};


Разве я не прав?
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38186988
petrav
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositum,

Извините =)
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38186991
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
petravКаждой вещи свое назначение. Использование перечислений по не прямой надобности родилось тогда, когда в стандарте не было такого:
Код: plaintext
1.
2.
3.
4.
class foo
{
    static std::size_t const Max = 128;
};


Разве я не прав?
В C этого до сих пор нет. Прошу не путать C с C++. :)
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187002
constexpr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
petravenum не угодил?пропущено...

А чем enum то не угодил?
Можно купить мерседес (черный!:) и поехать на нем траву косить.

Каждой вещи свое назначение. Использование перечислений по не прямой надобности родилось тогда, когда в стандарте не было такого:
Код: plaintext
1.
2.
3.
4.
class foo
{
    static std::size_t const Max = 128;
};


Разве я не прав?
Для C++ я бы сказал пока не появилось constexpr.
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187007
petrav
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
constexpr,

Да причем тут constexpr?

Enum - это по сути перечисление некоторых логических состояний объекта внимания:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
enum ПотанцуемПолежим
{
    НиХочу,
    НиДаю,
    НиБеру = 666, // WTF?!
    ДА = 500
};


Когда не было инлайн инициализации статических констант -- их заменяли enum-ами. Потому что это удобно.
Когда стат. константы появились -- перечисления обрели свое истинное назначение.
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187017
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В С ключевое слово const означает что данную переменную вы (тот модуль который видит это объявление) не можете изменять,но это не значит что в других модулях ее нельзя изменить.
Поэтому такие переменые нельзя изпользовать как границы массива - это не константы, а константные ссылки к переменным.
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187056
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyПоэтому такие переменые нельзя изпользовать как границы массива - это не константы, а константные ссылки к переменным.
Но ведь границы массива указываются целыми числами, которые передаются не по ссылке, а по значению. И ещё такой момент: если в C переменная объявлена как const, то разве компилятор не подставляет её непосредственное значение вместо имени этой переменной во всём коде при компиляции (за исключением const аргументов функции)?
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187069
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumИ ещё такой момент: если в C переменная объявлена как const, то разве компилятор не подставляет её непосредственное значение вместо имени этой переменной во всём коде при компиляции (за исключением const аргументов функции)?
Полистал K&R, и в начале 2-й главы прочёл это (причём ранее ведь уже читал это):
Chapter 2 - Types, Operators and ExpressionsThe ANSI standard has made many small changes and additions to basic types and expressions.
...
Objects may be declared const, which prevents them from being
changed.

Т.е. замена не происходит, а вместо этого при компиляции выполняется лишь проверка на то, чтобы в коде не присутствовало изменение переменной, помеченной как const.

Но ведь когда я компилирую код с опцией -std=c90, то ошибок не получаю, несмотря на то, что в качестве размера массива указываю const переменную. Т.е. может быть в C90 разрешили указывать переменные, помеченные как const, а автор книги писал о C89?

Обратите внимание на следующий код:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
/*
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), однако код компилируется без проблем.

Честно говоря, я в замешательстве...
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187073
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumAnatoly MoskovskyПоэтому такие переменые нельзя изпользовать как границы массива - это не константы, а константные ссылки к переменным.
Но ведь границы массива указываются целыми числами, которые передаются не по ссылке, а по значению.Во первых, у тебя кривой перевод учебника. В С нету "границ массива", там есть только "размер статического массива" и "размер динамически выделенного куска памяти".
Статический массив определяется на этапе компиляции, динамический в рантайме. Размер для обоих может быть только целым.

Compositum И ещё такой момент: если в C переменная объявлена как const, то разве компилятор не подставляет её непосредственное значение вместо имени этой переменной во всём коде при компиляции (за исключением const аргументов функции)?Нет, не подставляет.
Если ты сделал const переменную, то она будет создана в сегменте "только для чтения" и ты сможешь брать указатель на нее и читать ее (напрямую или через указатель). Но не сможешь изменять, иначе segmentation fault получишь.
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187074
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White OwlCompositum И ещё такой момент: если в C переменная объявлена как const, то разве компилятор не подставляет её непосредственное значение вместо имени этой переменной во всём коде при компиляции (за исключением const аргументов функции)?Нет, не подставляет.
Если ты сделал const переменную, то она будет создана в сегменте "только для чтения" и ты сможешь брать указатель на нее и читать ее (напрямую или через указатель). Но не сможешь изменять, иначе segmentation fault получишь.
Выше я уже отписался о том, что ответ на данный вопрос мною уже найден.

White OwlСтатический массив определяется на этапе компиляции, динамический в рантайме. Размер для обоих может быть только целым.
Это мне известно.
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187250
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositum,
White Owl,

Не следует мешать все в кучу.

Так вот.
Переменые (в широком смысле, включая константы) можно объявить со статическим размещением в сегменте данных (к ним относятся глобальные и статические переменные) и с автоматическим размещением в стеке (локальные нестатические).
Рассмотрим эти два варианта в применении к массивам и их размерам:
1) Если мы объявили статический массив
Код: plaintext
1.
char s[max]; // за пределами тел функций


то max там может быть только литеральной константой или enum.

Вот это не является ни тем ни другим:
Код: plaintext
1.
const int max = 100;


Как я уже выше писал, в C (но не в C++) const не означает что это константа, а означает что следующий за ним код не может модифицировать значение, а из других модулей оно вполне может модифицироваться.
Т.е. корректный пример демонстрирующий этот вариант такой:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
const int max = 100;
enum {
	Max = 100
};
char s1[max]; // ошибка компиляции: размер массива не константа
char s2[Max]; // ок
int main(void) {
	return 0;
}



2) Теперь расмотрим массив объявленный внутри функции (с автоматической памятью).
Здесь в С (и опять же не в С++) действуют совсем другие правила чем для статических массивов.
Размер локального массива вычисляется не при компиляции, а при входе в функцию при ее выполнении (я сейчас не рассматриваю оптимизации).
А поэтому в качестве размера массива там может быть любое целое выражение допустимое в С в том месте.
Код: plaintext
1.
2.
3.
4.
int main(void) {
	char a[все что угодно];	  // включая переменные const и вызовы функций
	return 0;
}
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187276
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyКак я уже выше писал, в C (но не в C++) const не означает что это константа, а означает что следующий за ним код не может модифицировать значение, а из других модулей оно вполне может модифицироваться.Не может.
Компилятор это пропустит, но программа упадет.
Код: plaintext
1.
2.
//m1.c
const int a=0;


Код: plaintext
1.
2.
3.
4.
5.
//m2.c
extern int a;
void foo() {
   a = 1;
}

Компилируется без проблем, а в рантайме мрет.
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187281
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White OwlAnatoly MoskovskyКак я уже выше писал, в C (но не в C++) const не означает что это константа, а означает что следующий за ним код не может модифицировать значение, а из других модулей оно вполне может модифицироваться.Не может.
Компилятор это пропустит, но программа упадет.И вообще, это один из способов стрельбы по своей ноге. Объяви переменную const а потом сделай присваивание ей через приведение типов. С глобальными переменными таким образом ты убьешь программу, а с локальным const выживет.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
const int a=0;
void foo() {
   (int)a = 1; // segmentation fault
}

void baz() {
   const int b =0;
   (int)b = 1; // ok
}
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187312
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
White Owl,

Суть моего объяснения выше не в том что есть возможность менять переменные const, а в том что с точки зрения языка const
это не константа, а значит не может быть размером массива, там где разрешены только константы.
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187320
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А насчет корректности модификации const - в языке когда делали эту фичу имели в виду такой код:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
// a.c
include<stdio.h>
const int max;
void f(void);
int main(void) {
  printf("%i\n", max);
  f();
  printf("%i\n", max);
  return 0;
}


Код: plaintext
1.
2.
3.
4.
5.
6.
// b.c
int max = 100;
void f(void)
{
    max = 1;
}



И это абсолютно корректный код. Модуль a.c не может модифицировать переменную max, а модуль b.c модифицирует, и a.c видит эти модификации.
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187346
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyИ это абсолютно корректный код.
Вообще-то нет. Напоминаю, что речь о C90. Указанный код компилироваться не будет. Директива include в C указывается так:
Код: plaintext
1.
#include<stdio.h>


Комментарии в стандарте C89/C90 указываются так:
Код: plaintext
1.
/* комментарий */


а не в виде //.

Даже если внести указанные мною попровки, то при компиляции получим ошибки (в принципе, ожидаемые):
терминалbush@host-nix:~$ cd ~/test
bush@host-nix:~/test$ gcc a.c b.c -o a.out -std=c90
/tmp/cccZd6Gp.o:(.data+0x0): multiple definition of `max'
/tmp/ccoZXZt0.o:(.rodata+0x0): first defined here
collect2: ошибка: выполнение ld завершилось с кодом возврата 1


Однако тема плавно куда-то ушла от заданного мною вопроса, как мне кажется. Я разобрался с вопросом темы. Проблема была в том, что изначально я указывал компилятору недостаточно опций и проверка на соответствие стандарту C90 проходила не столь педантично, как мне было нужно. Если выставить все нужные опции, то const действительно нельзя будет использовать (это ограничение закреплено в стандарте). На всякий случай покажу пример (нужные опции указал в комментарии, в начале кода - три варианта):
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
/*
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
*/
#include<stdio.h>

const int max = 100;

enum {
	Min = 0,
	Max = 100
};

int f(){
	return 100;
}

int main(void) {

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


Теперь я спокоен. :)
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187424
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumДаже если внести указанные мною попровки, то при компиляции получим ошибки (в принципе, ожидаемые):
терминалbush@host-nix:~$ cd ~/test
bush@host-nix:~/test$ gcc a.c b.c -o a.out -std=c90
/tmp/cccZd6Gp.o:(.data+0x0): multiple definition of `max'
/tmp/ccoZXZt0.o:(.rodata+0x0): first defined here
collect2: ошибка: выполнение ld завершилось с кодом возврата 1


Данная ошибка говорит о том что вы кроме исправления моих опечаток (уж простите, в форумном редакторе нет компилятора для проверки, но поверьте я знаю как записывать команду #include), внесли существенное изменение - добавили инициализацию константы в ее определение.
Иначе никак нельзя объяснить что в сегменте .rodata есть значение для этой константы.
Если пофиксить эту самодеятельность, то мой код нормально компилируется и работает при сборке командой
Код: plaintext
gcc a.c b.c -std=c90 -pedantic-errors
Специально для вас проверил это на версии gcc (GCC) 4.7.2 20120921

Теперь я спокоен. :)
Рано успокоились.
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187428
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyИначе никак нельзя объяснить что в сегменте .rodata есть значение
для этой константы.
А отсутствие слова extern тут точно никаким боком не влияет?..
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187438
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimitry SibiryakovAnatoly MoskovskyИначе никак нельзя объяснить что в сегменте .rodata есть значение
для этой константы.
А отсутствие слова extern тут точно никаким боком не влияет?..

Может и влияет.
Для начала нужно чтобы мы рассматривали один и тот же исходный код и версию компилятора и добились одинакового поведения.
А потом уже можно будет говорить, какое поведение стандартно, а какое нет.
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187443
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyДанная ошибка говорит о том что вы кроме исправления моих опечаток, внесли существенное изменение - добавили инициализацию константы в ее определение.
Иначе никак нельзя объяснить что в сегменте .rodata есть значение для этой константы.
Если пофиксить эту самодеятельность, то мой код нормально компилируется и работает при сборке командой
Код: plaintext
gcc a.c b.c -std=c90 -pedantic-errors
Специально для вас проверил это на версии gcc (GCC) 4.7.2 20120921

Теперь я спокоен. :)
Рано успокоились.
Проверил ещё раз. Да, вы правы, инициализацию добавлял. Убрал - заработало... Да, успокоился рано...
...
Рейтинг: 0 / 0
Константы (const) не могут служить границами массивов в C?
    #38187452
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimitry SibiryakovAnatoly MoskovskyИначе никак нельзя объяснить что в сегменте .rodata есть значение
для этой константы.
А отсутствие слова extern тут точно никаким боком не влияет?..

Погуглил: в С, extern - по умолчанию для переменных без инициализации. Так что от его добавления ничего не должно измениться.
...
Рейтинг: 0 / 0
25 сообщений из 27, страница 1 из 2
Форумы / C++ [игнор отключен] [закрыт для гостей] / Константы (const) не могут служить границами массивов в C?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]