Я наткнулся на небольшую проблему при попытке сделать константный-правильный код.
Я бы хотел написать функцию, которая принимает указатель на константные структуры, чтобы сказать компилятору "Пожалуйста, скажите мне, если я изменение структуры, потому что я действительно не хочу, чтобы".
Ей вдруг пришло в голову, что компилятор не позволит мне сделать это:
struct A
{
char *ptrChar;
};
void f(const struct A *ptrA)
{
ptrA->ptrChar[0] = 'A'; // NOT DESIRED!!
}
Что вполне понятно, потому что на самом деле является константой является сам указатель, а не тип, на который он указывает. Я бы хотел, чтобы компилятор, чтобы сказать мне, что я'м делаешь что-то не хочу делать, хотя, если это даже возможно.
Я использовал GCC, как мой компилятор. Хотя я знаю, что приведенный выше код должен быть легальным, я еще проверил, если он будет выдавать предупреждение в любом случае, но ничего не вышло. Мой командной строки:
gcc -std=c99 -Wall -Wextra -pedantic test.c
Можно ли обойти эту проблему?
Способ создать свой путь вокруг этого, в случае необходимости, является использование двух разных типов на один и тот же объект: один для чтения/записи типа а на одном-только тип.
typedef struct
{
char *ptrChar;
} A_rw;
typedef struct
{
const char* ptrChar;
} A_ro;
typedef union
{
A_rw rw;
A_ro ro;
} A;
Если функция должна изменять объект, он принимает чтение и запись тип в качестве параметра, в противном случае он принимает только для чтения типа.
void modify (A_rw* a)
{
a->ptrChar[0] = 'A';
}
void print (const A_ro* a)
{
puts(a->ptrChar);
}
Довольно интерфейса абонента и сделать его совместимым, вы можете использовать функции-обертки в качестве общего интерфейса к вашему АДТ:
inline void A_modify (A* a)
{
modify(&a->rw);
}
inline void A_print (const A* a)
{
print(&a->ro);
}
С помощью этого метода, " а " теперь могут быть реализованы как непрозрачный тип, чтобы скрыть реализацию для абонента.
Это пример интерфейса и реализации, или "Сокрытие информации" ПО-или, вернее, не прятаться ;-) -- вопрос. В C++ можно было бы просто иметь указатель частная и определить подходящие методы доступа государственного строительства. Или можно было бы определить абстрактный класс -- собой "интерфейс" и ... с аксессу. Правильной структуры будет реализовать это. Пользователи, не нужно создавать структуры экземпляры потребуется только ознакомиться с интерфейсом.
В C можно подражать, что, определив функцию, которая принимает указатель на структуру в качестве параметра и возвращает указатель на константный тип char. Для пользователей, которым не нужно создавать экземпляры этих структур, можно даже представить, что "пользователь заголовка" по которой не течет структуры'ы реализации, но только определяет манипулирующие функции с (или возврат, как на заводе) указатели. Таким образом, структура неполного типа (которые могут быть использованы только указатели на экземпляры). Эта модель эффективно имитирует то, что язык C++ не за кулисами с указателя this
.
Может быть, если вы решите использовать С11 можно реализовать универсальный макрос, который относится либо к постоянным или переменным версия этого же участника (вы должны также включать профсоюз в вашей структуре). Что-то вроде этого:
struct A
{
union {
char *m_ptrChar;
const char *m_cptrChar;
} ;
};
#define ptrChar_m(a) _Generic(a, struct A *: a->m_ptrChar, \
const struct A *: a->m_cptrChar)//, \
//struct A: a.m_ptrChar, \
//const struct A: a.m_cptrChar)
void f(const struct A *ptrA)
{
ptrChar_m(ptrA) = 'A'; // NOT DESIRED!!
}
Союз создает 2 устный перевод на один член. В m_cptrChar
- это указатель на константу типа char и m_ptrChar к не постоянной. Этот макрос решает, что в зависимости от типа его's параметр.
Единственная проблема заключается в том, что ptrChar_m макрос `` может работать только с либо указатель или объект этой структуры, а не обе.
Это известная проблема языка C, а не избежать. Ведь вы не вносите изменений в структуре, изменении отдельный объект через не как const
-квалифицированный указатель, полученный из структуры. константный
семантический был изначально разработан всего нужно отмечать память регионах как константа, которая физически не'т для записи, а не вокруг какой-либо проблемы в оборонительных программирования.
Мы могли бы скрыть информацию за какой-то "метод" по функции:
// header
struct A; // incomplete type
char *getPtr(struct A *);
const char *getCPtr(const struct A *);
// implementation
struct A { char *ptr };
char *getPtr(struct A *a) { return a->ptr; }
const char *getCPtr(const struct A *a) { return a->ptr; }
Нет, если вы не измените определение структуру:
struct A
{
const char *ptrChar;
};
Еще извитых решение, которое сохраняет старое определение структуры нетронутым, чтобы определить новую структуру с одинаковыми членами, чьи соответствующий указатель элементов: указывает на константный тип. Затем функция вызова изменяется, чтобы взять новую struct. Функция-обертка определено, что берет старую структуру, делает члена копия члена новой структуры и передает его функции.
Можете ССЗ предупредить меня об изменении поля с const struct в С99?
Вы не изменяя поля константные структуры.
Значение ключевого слова struct содержит указатель на неконстантный Чаре. птра-это указатель на константный А. структура, так что вы можете'т изменение структуры значения в сттэ. Так что вы можете't изменить указатель на char в (сттэ).Голец птра-&ака ГТ;ptrChar. Но при изменении значения в котором птра->ptrChar точки, т. е. значение в *(сттэ->Голец) птра-&ака ГТ;чар[0]. Единственный констант здесь являются структура, как и вы'повторно не меняя структуру, так что exacty есть "не нужные" и?
Если вы Don'т хотим, чтобы позволить изменение значения в которых структуру A'ы Чаре поле точки (через которые структура а), затем использовать
struct A
{
const char *ptrChar; // or char const *ptrChar;
};
Но, возможно, что вы думаете что вы делаете в F-это что-то вроде
void f(const struct A *ptrA)
{
const char c = 'A';
ptrA->ptrChar = &c;
}
Которые будут получать сообщение об ошибке от компилятора.