Передача Пустого параметра типа в C

Когда должен XML использоваться для персистентности данных вместо базы данных? Почти никогда. XML является транспортным языком данных. Это не спешит анализировать и неудобный запросить. Проанализируйте XML (не уничтожайте его!) и преобразовывают получающиеся данные в объекты области. Тогда сохраните объекты области. Главным преимуществом базы данных для персистентности является SQL, что означает неструктурированные запросы и доступ к общим инструментам и методам оптимизации.

8
задан Adam Lee 21 November 2009 в 17:37
поделиться

7 ответов

Вам нужно привести указатель к одному из этих трех типов, а затем использовать его. Примерно так:

MyType* p = (MyType*)element;
p->count++;

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

12
ответ дан 5 December 2019 в 05:19
поделиться

Вам нужно привести указатель к одному из этих трех типов, а затем использовать его. Примерно так:

MyType* p = (MyType*)element;
p->count++;

Однако вы должны быть уверены в типе объекта, который вы приводите, поскольку приведение объекта к неправильному типу может быть опасным.

Если вы не полагаетесь на ваши типы, имеющие совместимую компоновку (которая, вероятно, будет зависеть от реализации), вам также потребуется передать что-то, что поможет вашей функции определить правильное приведение для выполнения. На этом этапе вам может быть лучше использовать три отдельные функции и лучшую безопасность типов.

9
ответ дан 5 December 2019 в 05:19
поделиться

Вы должны привести его к фактическому типу, но вы можете получить неожиданные результаты в структурах, у которых нет свойства 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);
6
ответ дан 5 December 2019 в 05:19
поделиться

Если элемент .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 ++ ; довольно странно.

3
ответ дан 5 December 2019 в 05:19
поделиться

используйте приведение.

ClassName(element).count++

также ваш element.Count = element.Count ++; строка избыточна, вам просто нужно сделать element.count ++ (который увеличивает значение на единицу)

1
ответ дан 5 December 2019 в 05:19
поделиться

При компиляции 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), к которой она применяется; присвоение в исходном коде не требуется.

1
ответ дан 5 December 2019 в 05:19
поделиться

Проблема именно в этом:

Я предполагаю, что это происходит потому что компилятор не знает вид «элемента» перед рукой. Однако Я не понимаю, почему это не работает.

Вызов метода или данных члена по имени обычно не является функцией языков со статической типизацией.

Даже void * может быть только надежно приведено к T * , где T - тип, когда указатель на самом деле является указателем на этот тип.

В C ++ одна возможность состоит в том, чтобы все три типа унаследовали от одного и того же виртуального баса класс X, у которого есть метод Count (т.е. интерфейс ICountable). Затем приведение к X * и использование p-> Count . Это было бы идиоматическим C ++ - все классы реализуют один и тот же интерфейс и, следовательно, все они поддерживают этот метод. Это был бы поддерживаемый языком метод, аналогичный тому, чтобы полагаться на тот же трюк смещения структуры, показанный в ответе Томми Макгуайра: что делает структуры похожими по соглашению . Если бы вы изменили структуры или компилятор отклонился от стандарта для компоновки структур, вы были бы в затруднительном положении.

Я не могу избавиться от мысли, что это скорее игрушечная проблема, поскольку метод является настолько прост, что обычно его не оборачивают в функцию - можно просто назвать его встроенным: T t; t.Count ++; .

0
ответ дан 5 December 2019 в 05:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: