У меня есть структура в С, которая представляет собой ряд целых чисел:Структуры и постоянные структуры
typedef struct {
int* data;
unsigned start;
unsigned end;
} Range;
У меня есть одна функция, которая записывает значения в диапазоне
bool range_put(Range* const r, int value, unsigned idx)
{
if(r->start <= idx && idx < r->end)
{
r->data[idx] = value;
return true;
}
else
{
return false;
}
}
и одна функция, которая считывает из a
bool range_get(const Range* const r, int* const out, unsigned idx)
{
if(r->start <= idx && idx < r->end)
{
*out = r->data[idx];
return true;
}
else
{
return false;
}
}
Что бы я хотел сделать, это расширить эти функции, чтобы я мог иметь Rang e для константных целых чисел. Что-то вдоль линий
typedef struct {
const int* data;
unsigned start;
unsigned end;
} ConstRange;
Как я могу сделать range_get()
работать как на Range
и ConstRange
?
Одним из решений было бы просто дублировать функциональность range_get()
на новую функцию bool crange_get(const ConstRange*...)
, но я хотел бы сохранить количество функций на низком уровне.
Другим решением было бы объединять Range
(сомнительное ли это или нет «разрешено»)
typedef union {
ConstRange const_range;
struct {
int* data;
unsigned start;
unsigned end;
}
} Range;
Недостатком здесь является то, что синтаксис вызова range_get()
становится немного более сложным при переходе в Range
Range range;
...
range_get(&range.const_range ...);
Каковы другие альтернативы, поддерживающие количество функций и сложность в использовании функций вниз?
Range range;
ConstRange const_range;
...
range_get(&range ...);
range_get(&const_range ...);
Вы знаете, что, когда у вас есть 'const int *', который указывает на некоторую память, вы не можете изменить или даже * инициализировать * память через свой указатель. Если вы используете, например, 'malloc', чтобы выделить память, тогда вы будете застрять с неинициализированной памятью на всю жизнь. Решение может состоять в том, чтобы отслеживать, какие элементы в диапазоне, которые были записаны на * один раз *, anbd не позволяют им записываться снова. Это может быть выполнено с помощью массива флагов, по одному флагу для каждого элемента в диапазоне.Что касается const/non-const part, достаточно простого булевского флага. –
@JoachimPileborg «... тогда вы не можете изменить ...» - вы ** не должны **. 'const 'является гарантией, предоставленной программистом, не выполняемой компилятором. Это просто позволяет компилятору предупредить пользователя, но не препятствует ему стрелять в ногу. – Olaf
Вы можете использовать «объединение» с двумя значениями. Используйте 'const int *' для всех, кроме функций модификации. – Olaf