Синтаксис C Cast, как насчет сложных приведений? - PullRequest
0 голосов
/ 04 ноября 2011

Мне нужна помощь в синтаксисе C, больше о синтаксисе приведения C.
Вся информация, которую я нашел в Интернете, касается простых приведений типа (int) или (char) и т. Д.
Я всегда получаю застрял в приведении void* к массиву или многомерному массиву или указателям на такие вещи, но я никогда не знаю, как это сделать! Все, что я делал в этих случаях, пытался что-то вроде (char []) или (char *[]) или (*char []), не зная, что я делаю, до тех пор, пока не получу никаких ошибок при приведении типов.

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

main () {
   int data1, data2;
   char data3, data4;
   void *function_data[] = {data1, data2, data3, data4};
   some_function (function_data);
   return;
}


some_function (void *data) {
   void *function_d[4];
   function_d = (void *[]) data; //It not work, how to cast data?
}

РЕДАКТИРОВАТЬ: Я написал неправильно, я думал, что это не важно, поэтому я изменил данные переменных * моего кода для лучшего понимания.

Ответы [ 4 ]

2 голосов
/ 04 ноября 2011

Ваша проблема в том, что void *function_d[4]; создает новый массив. Вы не можете присвоить ему другой массив. function_d должно быть типа void**.

1 голос
/ 05 ноября 2011

Основная идея состоит в том, чтобы использовать определение типа предполагаемого типа без имени переменной и поместить в скобки в качестве приведения к этому типу.Например:

int c;
c = (int) 4;

и

char * (*functionptr)(float, double);
functionptr = (char * (*)(float, double))myfunction;

Конечно, всегда предполагается, что приведение типа возможно и имеет смысл.Имейте в виду: C не предотвращает большинство бессмысленных приведений, поэтому вам нужно позаботиться о себе.

В вашем случае, function_data определяется как массив указателей на void.Следовательно, все данные должны иметь тип void **, как уже указывал Кейт.Вызывая some_function с function_data в качестве параметра, вы передаете указатель на function_data[0] в функцию.Чтобы ваша функция снова использовала ее в качестве массива из 4 указателей для аннулирования, вам необходимо использовать приведение, как вы это делали (void * []).Однако массив function_d является массивом, резервирующим также пространство для четырех указателей, и вы не можете изменить указатель на function_d (он имеет тип void * * const!).Чтобы сделать то, что вам нужно, вам понадобится неконстантный указатель, такой как

void * * function_d = (void*[])data;

. Затем вы все равно можете использовать его так же, как function_data, используя подписку как массив.function_d[2] даст вам значение, равное *data3.

0 голосов
/ 05 ноября 2011

Несколько проблем:

Это не сработает:

int data1, data2;
char data3, data4;
void *function_data[] = {data1, data2, data3, data4};

, поскольку int и char не совместимы с void *.Это можно исправить следующим образом:

void *function_data[] = {&data1, &data2, &data3, &data4};

, поскольку int * и char * совместимы с с void *.

Когда вы передаете function_data вsome_function, выражение массива преобразуется в значение указателя, поэтому some_function получает void **.Вы можете использовать оператор указателя на указателе, как если бы он был массивом:

some_function(function_data);
...
void some_function(void **data)
{
  int *x = data[0];  // remember, we stored the *addresses*
  int *y = data[1];  // of data1, data2, data3, and data4;
  char *a = data[2]; // since the type of data is void **,
  char *b = data[3]; // the type of data[i] is void *.
  ...
}

IOW, не нужно для приведения data к типу массива, чтобыиспользуйте это как массив.

0 голосов
/ 05 ноября 2011

Вы не можете назначить объект массива.

Как объявляются data1, data2, data3 и data4?

void* является (или может использоваться как) универсальным типом указателя. Это может дать вам огромную гибкость, но также может помешать проверке типа.

function_data - массив из 4 указателей на void. В вызове some_function (function_data) он неявно преобразуется в void**, указатель на первый элемент.

some_function ожидает void*, а не void** - но любой тип указателя (кроме указателя на функцию) может быть неявно преобразован в void*, поэтому компилятор не будет жаловаться на вызов.

Вот версия вашей программы, которая, по крайней мере, верна (я думаю).

#include <stddef.h>

void some_function(void **data, size_t count);

int main(void) {
    void **data1, **data2, **data3, **data4;
    void *function_data[] = { *data1, *data2, *data3, *data4 };
    some_function (function_data,
                   sizeof function_data / sizeof function_data[0]);
    return 0;
}

void some_function(void **data, size_t count) {
    size_t i;
    for (i = 0; i < count; i ++) {
        /*
         * do something with data[i], which is of type void*
         */
    }
}

Обратите внимание, что data1 и друзья не инициализированы, поэтому поведение этой программы не определено. Я подозреваю, что вы хотели написать что-то вроде:

void *function_data[] = { &data1, &data2, &data3, &data4 };

но трудно сказать, что вы пытаетесь сделать.

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

И я исправил объявления для main и some_function и добавил в верхнюю часть объявление для some_function, чтобы оно было видно при его вызове.

Вы должны всегда явно объявлять тип возвращаемого значения для всех ваших функций. В версии C 1990 года вы можете опустить ее, и по умолчанию она будет int (но все равно лучше явно объявить ее как int). В версии C 1999 года тип является обязательным, и вы не можете вызывать функцию без видимого объявления.

Опять же, из кода, который вы нам показали, трудно понять, что именно вы пытаетесь сделать, из-за чего сложно догадаться, как это сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...