Когда должен XML использоваться для персистентности данных вместо базы данных? Почти никогда. XML является транспортным языком данных. Это не спешит анализировать и неудобный запросить. Проанализируйте XML (не уничтожайте его!) и преобразовывают получающиеся данные в объекты области. Тогда сохраните объекты области. Главным преимуществом базы данных для персистентности является SQL, что означает неструктурированные запросы и доступ к общим инструментам и методам оптимизации.
Вам нужно привести указатель к одному из этих трех типов, а затем использовать его. Примерно так:
MyType* p = (MyType*)element;
p->count++;
Однако вы должны быть уверены в типе объекта, который вы преобразовываете, поскольку приведение объекта к неправильному типу может быть опасным.
Вам нужно привести указатель к одному из этих трех типов, а затем использовать его. Примерно так:
MyType* p = (MyType*)element;
p->count++;
Однако вы должны быть уверены в типе объекта, который вы приводите, поскольку приведение объекта к неправильному типу может быть опасным.
Если вы не полагаетесь на ваши типы, имеющие совместимую компоновку (которая, вероятно, будет зависеть от реализации), вам также потребуется передать что-то, что поможет вашей функции определить правильное приведение для выполнения. На этом этапе вам может быть лучше использовать три отдельные функции и лучшую безопасность типов.
Вы должны привести его к фактическому типу, но вы можете получить неожиданные результаты в структурах, у которых нет свойства count в том же месте.
typedef struct _A
{
int count;
int x;
}A;
int changeCount(void* element)
{
((A*)element)->Count++;
return 1;
}
Также помните, что если вы передадите указатель на структуру, которая выглядит следующим образом: вы увеличиваете поле x, а не счетчик.
typedef struct _B
{
int x;
int count;
}B;
B st;
B* pst = &st;
changeCount(pst);
Если элемент .Count
такой же type для каждого из этих 3 типов, то вы также можете использовать макрос. Предполагая, что это int, вы можете сделать следующее:
#define changeCount(a) _changeCount((a), &(a)->Count)
int _changeCount(void* element, int *count)
{
(*count)++;
return 1;
}
Это будет работать, потому что адрес a.Count
будет разрешен при вызове функции, а не после (когда вы больше не знаете тип) . Я предполагаю, что при вызове функции у вас есть правильный тип. Итак Sometype x; changeCount (x);
будет работать, но передача чего-то, что уже является (void *)
, не будет.
Также ваше исходное выражение element.Count = element.Count ++ ;
довольно странно.
используйте приведение.
ClassName(element).count++
также ваш element.Count = element.Count ++; строка избыточна, вам просто нужно сделать element.count ++ (который увеличивает значение на единицу)
При компиляции C отбрасывает [1] большую часть информации о типе, оставляя только смещения. Итак, ваша функция будет компилироваться примерно так, в псевдокоде:
changeCount:
assign *(*(stack_ptr + offset_element) + offset_Count) + 1
to *(stack_ptr + offset_element) + offset_Count;
assign 1 to return_value;
pop
stack_ptr - это расположение кадра стека, который был создан при вызове changeCount, offset_element - это расположение аргумента элемента относительно stack_ptr, но что такое offset_Count? Имейте в виду, что все, что компилятор знает о вашем коде, - это только то, что вы показали в своем примере; element - это общий указатель, а не указатель ни на что. Вам нужно будет сообщить компилятору, на какой элемент указывает, путем преобразования или присвоения его переменной [2]:
typedef struct { int Count; } counted_t;
int changeCount(void* element)
{
counted_t* counted = element;
counted.Count++;
return 1;
}
Эта функция сгенерирует практически тот же (псевдо) код, что и выше, но теперь компилятор знает, какое смещение Граф должно быть.
Вы упоминаете, что существует три возможности для типа того, на что указывает элемент. Есть несколько способов справиться с этим: выделенное объединение или «унаследованная» структура. Для выделенного объединения используйте, скажем, структуру, в которой один элемент является перечислением, определяющим, какая из трех возможностей, а другой элемент является объединением трех возможных структур; это примерно то, что языки ML (OCaml, Haskell и т. д.) называют алгебраическим типом данных или тем, что представляет собой объединение в Паскале. Для «наследования» вы можете использовать определения типов:
typedef struct { counted_t counted; int i; } counted_int_t;
typedef struct { counted_t counted; double d; } counted_double_t;
typedef struct { counted_t counted; char* s; } counted_charptr_t;
В этом случае вы можете использовать приведенную выше функцию changeCount и передать указатель на countted_int_t, countted_double_t или countted_charptr_t.
Что происходит, так это то, что компилятор заложит из трех структур с элементом Count в "потомке" структуры в том же месте , пока элемент countted_t является первым . (По крайней мере, в каждом компиляторе, который я когда-либо использовал, и в каждом бите кода, который я видел. Я думаю, что в какой-то момент это вошло в стандарт C, но это очень нормальная идиома.)
[1] За исключением отладочной информации , если вы сказали компилятору испустить его. Однако ваша программа не будет иметь доступа к этой информации, поэтому в этом случае она не поможет.
[2] Операция x ++ (постинкремент) увеличивает переменную (ну, lvalue), к которой она применяется; присвоение в исходном коде не требуется.
)[1] За исключением отладочной информации, если вы указали компилятору ее выдачу. Однако ваша программа не будет иметь доступа к этой информации, поэтому в этом случае она не поможет.
[2] Операция x ++ (постинкремент) увеличивает переменную (ну, lvalue), к которой она применяется; присвоение в исходном коде не требуется.
)[1] За исключением отладочной информации, если вы указали компилятору ее выдачу. Однако ваша программа не будет иметь доступа к этой информации, поэтому в этом случае она не поможет.
[2] Операция x ++ (постинкремент) увеличивает переменную (ну, lvalue), к которой она применяется; присвоение в исходном коде не требуется.
Проблема именно в этом:
Я предполагаю, что это происходит потому что компилятор не знает вид «элемента» перед рукой. Однако Я не понимаю, почему это не работает.
Вызов метода или данных члена по имени обычно не является функцией языков со статической типизацией.
Даже void *
может быть только надежно приведено к T *
, где T - тип, когда указатель на самом деле является указателем на этот тип.
В C ++ одна возможность состоит в том, чтобы все три типа унаследовали от одного и того же виртуального баса класс X, у которого есть метод Count (т.е. интерфейс ICountable). Затем приведение к X *
и использование p-> Count
. Это было бы идиоматическим C ++ - все классы реализуют один и тот же интерфейс и, следовательно, все они поддерживают этот метод. Это был бы поддерживаемый языком метод, аналогичный тому, чтобы полагаться на тот же трюк смещения структуры, показанный в ответе Томми Макгуайра: что делает структуры похожими по соглашению . Если бы вы изменили структуры или компилятор отклонился от стандарта для компоновки структур, вы были бы в затруднительном положении.
Я не могу избавиться от мысли, что это скорее игрушечная проблема, поскольку метод является настолько прост, что обычно его не оборачивают в функцию - можно просто назвать его встроенным: T t; t.Count ++;
.