Неверный тип указателя с typedef - PullRequest
2 голосов
/ 29 июня 2010

У меня проблемы при вызове функции, принимающей указатель на строку в качестве параметра. Мне нужно получить имя элемента.

// method
void getStringFromCsv( char ** str );

Позвольте мне представить структуры, с которыми я работаю (не написано мной и является частью гораздо большего проекта, я не могу их изменить)

// typedefs
typedef char      T_CHAR64[64];
typedef T_CHAR64  T_SYMBOL;

// generic element
typedef struct Element
{
  T_SYMBOL  name; 
} T_Element;

// csv element
typedef struct CsvElement
{
  Element * pElement;
  int   id;
} T_csvElement;

Итак, я думал, что вызову эту функцию следующим образом:

T_Element * pData; // Not null, filled earlier
getStringFromCsv( &pData->pElement->name );

Но это не работает (предупреждение: передача аргумента 1 из STR_toCsv из несовместимого типа указателя). Я использую gcc с NetBeans 6.8.

Я пробовал много вещей ...

T_SYMBOL foo = "foo";
T_SYMBOL * pFoo = &foo;

getStringFromCsv( pDef->name, &pFoo ); // error : passing from incompatible pointer type

T_CHAR * pBar = &foo;      // error : init from incompatible pointer type
T_CHAR * pBaz = &(foo[0]); // OK

getStringFromCsv( pDef->name, &pBaz ); // OK

T_SYMBOL * pFooTest = &(foo[0]); // error : init from incompatible pointer type

... но в итоге бросил имя на символ **:

getStringFromCsv( (char**) &pData->pElement->name );

Что не так с моим кодом? В основном, SYMBOL = CHAR *, верно? Почему СИМВОЛ *! = ЧАР **? Я почти уверен, что упускаю что-то простое, но сейчас ... Ничего не пришло.

EDIT Вот getStringFromCsv:

void getStringFromCsv( char ** data )
{
  // pDesc is defined and not null
  csvDescriptorCat( pDesc, *data);
  csvDescriptorCat( pDesc, "\t");
}

void csvDescriptorCat( CsvDescriptor * pDesc, char* str)
{
  int len;
  if( str != NULL)
  {
    len = strlen(str);
    strcpy( &pDesc->line[pDesc->pos], str);
    pDesc->pos += len;
  }
}

Ответы [ 5 ]

2 голосов
/ 29 июня 2010

name - это массив символов, поэтому & name дает вам указатель на char [64], как уже ответила Вики. Но приведение делает вещи хуже, потому что оно говорит компилятору обрабатывать первые символы массива как указатель на реальный массив.

См. C-FAQ: http://c -faq.com / aryptr / aryptr2.html

Я думаю, вы можете использовать временный символ * здесь:

char *tmp = pData->pElement->name; // array decays to pointer
getStringFromCsv(&tmp);

Если это ожидается функцией. Ожидая char**, убедитесь, что он не пытается перераспределить память. Для простого заполнения этого вполне достаточно char*.

2 голосов
/ 29 июня 2010

Если вы хотите передать &pData->pElement->name в функцию, функция должна быть объявлена ​​как:

void getStringFromCsv(T_SYMBOL * str);

В качестве альтернативы вы можете использовать временную char * в качестве предлагаемой защиты - но в этом нет особого смыслаЭто происходит потому, что любые обновления этого char * значения не могут быть использованы - член ->name нельзя изменить, так как это массив.

Вы также можете просто объявить функциюкак:

void getStringFromCsv( char * str );

... и вызвать его как:

getStringFromCsv( pData->pElement->name );

(В этом случае функция все еще может изменить содержимое ->name массив. Что вы не можете сделать, это изменить положение самого массива).


Кроме опции Secure, есть другой способ, если ваш компилятор поддерживает составные литералы C99:

getStringFromCsv( &(char *){ pData->pElement->name } );
1 голос
/ 29 июня 2010

Увы, один из маленьких секретов C, о которых вам не говорят, массив - это не то же самое, что указатель.если x определен как int x [5] или как угодно, & x == x.Попробуйте этот код ниже:

#include <stdio.h>
int main(int argc, const char *argv[])
{
   char x [5];
   char *y;

   printf("%08x\n", x);
   printf("%08x\n", &x);
   printf("%08x\n", y);
   printf("%08x\n", &y);

   return 0;
}
0 голосов
/ 29 июня 2010

Учитывая это: http://c -faq.com / decl / strlitinit.html

char  a[4] = "hello";
char* p = "hello";

Это не одно и то же (даже если они кажутся). Так что мои СИМВОЛ и ЧАР * не могут быть обменены, верно?

Есть ли обходной путь или другое решение?

0 голосов
/ 29 июня 2010

Да, под обложками T_SYMBOL обрабатывается как символ *. Но вы объявили его как char [64], так что вы передаете указатель на char [64], а не указатель на указатель на символ. Компилятор отслеживает это для вас.

Лично в этой ситуации я бы просто произнес это, как вы сделали в конце вашего вопроса.

...