Почему я получаю эту ошибку? void* не является указателем на тип объекта.

#c #c #linux #gcc #g

#c #c #linux #gcc #g

Вопрос:

 void *stackAddr[NUM_THREADS];

stackAddr[i] = malloc(STACKSIZE);
 

Компилятор (g 4.4.3) жалуется, где вызывается malloc …

 warning: pointer of type ‘void *’ used in arithmetic
error: ‘void*’ is not a pointer-to-object type
 

Если вам интересно увидеть весь код, вот он…

 #include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define NUM_THREADS 4

void *stackAddr[NUM_THREADS];
pthread_t thread[NUM_THREADS];
pthread_attr_t attr;

void *BusyWork(void *t)
{
   int i;
   long tid;
   double result=0.0;
   tid = (long)t;

   printf("Thread %ld starting...n",tid);
   for ( i = 0; i < 1000; i  )
   {
      result = result   sin(i*tid) * tan(i*tid);
   }
   printf("Thread %ld done. Result = %en", tid, result);
   pthread_exit((void*) t);
}

void pthread_create_with_stack( pthread_t * pthread, void *(*start_routine) (void *), int tid )
{
    const size_t STACKSIZE = 0xC00000; //12582912
    void *stackAddr;
    int rc;
    size_t i;
    pthread_t thread;
    pid_t pid;

    stackAddr[tid] = malloc(STACKSIZE); // Error here!
    pthread_attr_setstack(amp;attr, stackAddr[tid], STACKSIZE);

    rc = pthread_create( pthread, amp;attr, start_routine, (void*)tid );
}

int main (int argc, char *argv[])
{
   int rc;
   long t;
   void *status;

   /* Initialize and set thread detached attribute */
   pthread_attr_init(amp;attr);
   pthread_attr_setdetachstate(amp;attr, PTHREAD_CREATE_JOINABLE);

   for(t=0; t<NUM_THREADS; t  ) 
   {
      printf("Main: creating thread %ldn", t);
      rc = pthread_create_with_stack(amp;thread[t], BusyWork, t); 
      if (rc) 
      {
         printf("ERROR; return code from pthread_create() is %dn", rc);
         exit(-1);
      }
   }

   /* Free attribute and wait for the other threads */
   pthread_attr_destroy(amp;attr);
   for(t=0; t<NUM_THREADS; t  ) 
   {
      rc = pthread_join(thread[t], amp;status);
      if (rc) 
      {
         printf("ERROR; return code from pthread_join() is %dn", rc);
         exit(-1);
      }
      printf("Main: completed join with thread %ld having a status"   
            "of %ldn",t,(long)status);
    }

    printf("Main: program completed. Exiting.n");
    pthread_exit(NULL);
}
 

Комментарии:

1. Какая строка кода выдает эту ошибку? malloc Строка?

2. Покажите фактический код, здесь нет ошибки.

3. @trojanfoe, да, строка malloc.

4. @Daniel, зачем использовать char *, когда мне действительно требуется void * .

5. Ошибка не в этом коде. Делает ли реальный код что-то вроде попытки добавить смещение к результату malloc() ?

Ответ №1:

Вы объявляете локальную переменную void *stackAddr , которая затеняет глобальный stackAddr массив.

Более того, это не массив, и применение оператора [] подстрочного индекса пытается сместить и разыменовать void указатель, отсюда и ошибка компиляции.

Разыменование и арифметика указателей на указатели void не разрешены стандартом, поскольку sizeof(void) не определены.

Комментарии:

1. @MetallicPriest: Да, это так. pthread_create_with_stack имеет локальную переменную void *stackAddr .

2. Как вы «не делаете ничего подобного», когда на самом деле вы именно это и делаете?

3. А, понятно! Спасибо за ваши ответы! Kerrek SB, Blagvoest фактически изменил свой ответ. Я прокомментировал его предыдущий ответ.

Ответ №2:

Вы перепутали свое объявление:

 void *stackAddr;
 

должно быть:

 void *stackAddr[];
 

(Вам также может потребоваться установить размер массива.)

Затем вы пытаетесь сделать это:

 stackAddr[tid] = malloc(STACKSIZE);
 

Итак, вы обращаетесь к элементу массива a void* .

Комментарии:

1. @MetallicPriest: нет, это не так. По крайней мере, я знаю, кто делает эти замечательные -1-ы..

2. Присмотритесь повнимательнее к своей pthread_create_with_stack функции. [] В вашем объявлении отсутствует.

3. @yi_H, хахаха, извини, чувак, удалил мой комментарий и поддержал его. Mystical комментировал локальный stackAddr, в то время как я просматривал глобальный, который объявлен как массив. На самом деле проблема была локальной, которую необходимо устранить.

Ответ №3:

Теперь, когда вы опубликовали реальный код, я предполагаю, что ошибка заключается в pthread_create_with_stack том, что у вас есть локальная переменная void * stackAddr , которая скрывает глобальный массив.

Похоже, вам следует просто удалить локальную переменную.

Ответ №4:

То, что вы опубликовали первым, не является проблемой.

 void *stackAddr[NUM_THREADS];
 

Но в коде у вас есть что-то еще:

 void *stackAddr;
 

поэтому компилятор пытается использовать эту локальную переменную и, конечно же, не может скомпилироваться..

Ответ №5:

В pthread_create_with_stack , у вас есть этот код:

 void *stackAddr;
...
stackAddr[tid] = malloc(STACKSIZE)
 

Выражение stackAddr[tid] пытается выполнить арифметические вычисления для a void* .

Ответ №6:

В C указатели void не имеют атрибутов, включая size. В результате вы не можете вычислить адрес смещения для пустот i-числа с начала массива. Именно спецификация определенного индекса в массиве вызывает ваши математические проблемы.

Ответ №7:

В опубликованной вами версии stackAddr это не массив, которому вы присваиваете значение stackAddr[tid] . Компилятор заменяет это выражением в *(stackAddr tid) скобках , оценивающим значение to stackAddr tid * sizeof(void) , поэтому компилятор предупреждает вас об sizeof(void) этом .

Комментарии:

1. Компилятор знает размер и выравнивание всех полных типов, в том числе void* . Судя по именам переменных, OP нуждается в массиве для отслеживания количества блоков памяти, которые будут использоваться в качестве стеков потоков.

2. Все это четко указано стандартом: void* достаточно велико, чтобы содержать любой указатель на объект. Выравнивание не является частью языка. Вам нужны указатели void именно для результата вызовов malloc() or ::operator new() .

3. void * будет того же размера, что и, скажем, char * и выравнивание не имеет к этому никакого отношения. malloc() возвращает void * итак, в чем проблема? Я сам этого не вижу.

4. Хорошо, я постараюсь помнить об этом, хотя очень редко я имею дело с void * s напрямую. Спасибо за разъяснение. Я написал свой первоначальный комментарий как предположение о том, на что жаловался компилятор, прежде чем был опубликован новый код (с новым объявлением внутри функции). Я обновил свое предположение, чтобы просто объяснить предупреждение, но, конечно, другие ответы здесь действительно охватывают то, что не так.