LINUX.ORG.RU

Указатель на функцию

 ,


0

1

Всем привет, возникла тут непонятная ситуация, и, может быть, кто-нибудь поможет разобраться, буду очень признателен. Проблема связана с указателем на void, преобразованием и указателем на функцию, основные моменты:

void add_num(void *, void *);
void add_str(char *a, char *b);


void (*p)(void*,void*);

if (number) {
    p = &add_num;
} else {
    p = &add_str;
}

Ну и, соответственно, проблема в том, что в 'p = &add_num;' все нормально, потому что указатели на void, сама функция:

void add_num(void *a, void *b) {
    int one, two, result;
    char *c = a;
    char *d = b;
    
    
    printf("Test2, %s:%s\n", c, d);
    one = atoi(c);
    two = atoi(d);
    result = one+two;
    printf("Result = %d\n", result);
    
    itoa(result, r);
}
Тут мы получаем void, переприсваиваем в 'char *' и все работает.

А вот в случае с 'p = &add_str;' Я получаю вот это:

'main.c:38:11: warning: assignment from incompatible pointer type [enabled by default]'

Ну и собственно мой вопрос - программа-то работает, но как избавиться от этого сообщения и что вообще не так? Можно, конечно, сделать так же как и с 'p = &add_num;', но должен же быть и другой путь? Ну и весь код программы:

#include <stdio.h>
#include <stdlib.h>

void add_num(void *, void *);
void add_str(char *a, char *b);
void itoa(int i, char f[]);
void reverse(char rline[]);
char r[200];

int main(int argc, char **argv) {
    char c, number;
    void (*p)(void*,void*);

    number = 0;
    printf("Testing\n");
    printf("%s and %d\n", argv[1], argc);
    
    while ( --argc > 0 && ( **++argv == '-') ) {
        while ( (c = *++argv[0]) ) {
            printf("Test c=%c\n", c);
            switch(c) {
            case 'n':
                number=1;
                break;
            default:
                printf("Please enter valid key\n");
            }
            
        }
    }
    
    /* argv[2] argv[3] */
    printf("Number = %d\n", number);
    
    if (number) {
        p = &add_num;
    } else {
        p = &add_str;
    }
    
    
    
    (*p)((void *)argv[0], (void*)argv[1]);
    printf("test1: %s:%s\n", argv[0], argv[1]);
    /* add_num(argv[0], argv[1]); */
    
    printf("Finally result = %s\n", r);
    
    

    return 0;
}


void add_num(void *a, void *b) {
    int one, two, result;
    char *c = a;
    char *d = b;
    
    
    printf("Test2, %s:%s\n", c, d);
    one = atoi(c);
    two = atoi(d);
    result = one+two;
    printf("Result = %d\n", result);
    
    itoa(result, r);
}


void itoa(int n, char s[]) {
    int i = 0;
    int sign;
    //for (i = 0; i < 5;s[i++] = 5 + '0')
    //sign = ( n < 0) ? -1: 1;
    if ( ( sign = n )  < 0)
        n = -n;
    //printf("%d\n", sign);
    
    if ( sign < 0 )
        i++;
    //printf("%d\n", i);
    do {
        //s[i++] = n % 10 - '0';
        //n /= 10;
        s[i++] = n%10 +'0';
        //n /= 10;
        //printf("%d\n", s[i - 1]);
        
    //} while ( n > 0);
    } while ( ( n/=10 ) > 0 );
    
    if (sign < 0)
        s[i++] = '-';
    s[i] = '\0';
    
    
    
    //printf("%d\n", sign);
};


void reverse(char rline[])
{
  int i,j;
  char temp;

  for(i=0;rline[i]!='\0';++i)
    ;
  --i;
  if(rline[i]=='\n')
  --i;

  j = 0;

  while(j < i)
  {
    temp = rline[j];
    rline[j] = rline[i];
    rline[i] = temp;
    --i;
    ++j;
  }
}

void add_str(char *a, char *b) {
    int i;
    i = 0;
    
    while ( *a != '\0' ) {
        r[i++] = *a;
        a++;
    }
    
    /* if ( *a == '\0')
        i++; */
    while (*b != '\0') {
        printf("Test5: %s\n", b);
        r[i++] = *b;
        b++;
    }
    
}

Ответ на: комментарий от anonymous

если бы знал как, я вообще думал что это какая-то мифическая фигура и он сам материализуется когда нужен, так вот час настал, а его все нет и нет

Kronick
() автор топика
Ответ на: комментарий от anonymous

Шикарно, это работает, примерно такую запись и видел в K&R. Вот честно, я дня 4 просидел над этим моментом, перечитал все что мог и так и не мог понять как же сделать то, что мне надо. Я попробую объяснить что тут происходить, очень прошу, поправьте меня если я где не прав:

Берем ссылку на addstr, и соответственно получаем то что должна иметь функция на входе и выходе, и меняем тип с чего бы там не было на 'void (*)(void*,void*)', это и называется cast, все верно? Вообще я думал что запись 'void (*)' значит другое, думал что в звездочку поставится то, что будет после объявления, ну вроде такой перестановки после этого действия: с

p = (void (*)(void*,void*))&add_str;
изменится на:
p = ( void (addstr)(void*, void*) );

Хотя может так оно и работает, или я что-то путаю?

Kronick
() автор топика

The behavior is undefined in the following circumstances:

A pointer is used to call a function whose type is not compatible with the pointed-to type (6.3.2.3).

b0r3d0m
()
Ответ на: комментарий от Kronick

Берем ссылку на addstr, и соответственно получаем то что должна иметь функция на входе и выходе, и меняем тип с чего бы там не было на 'void (*)(void*,void*)', это и называется cast, все верно?

Да.

Вообще я думал что запись 'void (*)' значит другое, думал что в звездочку поставится то, что будет после объявления,

Ни в какую звездочку ничего никогда не «подставлятся», это точно такой же каст как и (uint32_t *)foo, например. Разберись с синтаксисом для указателей на функции.

Задача-бонус: разберись с тайпдефами для указателей на функции.

anonymous
()
Ответ на: комментарий от Kronick

Берем ссылку

какой-то странный у тебя си

anonymous
()
Ответ на: комментарий от anonymous

Отлично, спасибо за ответ, я не думал что кто-то ответит если честно.Вот я как раз и разбираюсь с синтаксисом указателей на функции, тут и встретил такие проблемы. Тайпдефы будут дальше по книжке, K&R и все такое, если они так сделали книжку, в таком порядке, то на то явно есть причина.

Kronick
() автор топика
Ответ на: комментарий от b0r3d0m

Это я встречал, но не понял как это поправить, поэтому и спросил, как оказалось я не знал толком про приведение типов

Kronick
() автор топика
Ответ на: комментарий от Kronick

K&R и все такое, если они так сделали книжку, в таком порядке, то на то явно есть причина.

Ну, началось. А если завтра тебе драгонбук или taocp предложат читать? А из окна прыгнуть?

anonymous
()
Ответ на: комментарий от anonymous

У меня есть план и я его придерживаюсь. Вот захотел выучить С - взял книжку и учусь по ней, что плохого?

Kronick
() автор топика
Ответ на: комментарий от Kronick

Плохого то, что не подвергаешь сомнению «авторитеты». Такими темпами вырастешь в гнусного мудака, который будет топить за «философию юникс» ну или там за сиплюсплюс какой-нибудь.

anonymous
()
Ответ на: комментарий от anonymous

Иногда без этого, к сожалению, никак. man dlsym, например.

anonymous
()
Ответ на: комментарий от anonymous

Как по мне гнусные мудаки - это как раз те, кто в самом начале обучения споря со всеми, везде лезут со своим мнением, когда ничерта не понимают. Много детей в школе спорят с учителем когда им говорят что 2*2=4? Я же учу саму основу языка, синтаксис, я прекрасно знаю что такое учебный план и зачем нужен определенный порядок в изучении чего-то. Если его не соблюдать - то вполне можно нахвататься обрывочных знаний всего подряд и вырасти говнокодером. Я же хочу получить базу в полном объеме, в K&R она есть и она хорошо структурирована, я в этом уже убедился. А вот когда буду знать это - там уже буду делать что-то сам и понимать где правильно, а где нет.

Kronick
() автор топика
Ответ на: комментарий от anonymous

Вопрос странный, но что это значит? Не на всех ОС есть?

Kronick
() автор топика
Ответ на: комментарий от Kronick

Желаю тебе все таки раздавить в себе личинку школьной училки/вертухая. А нет - ну что ж, ждем твоих постов про фейлософию юнегз.

Привет.

anonymous
()
Ответ на: комментарий от Kronick

Я же привёл цитату, там всё чётко написано:

The behavior is undefined in the following circumstances:

A pointer is used to call a function whose type is not compatible with the pointed-to type (6.3.2.3).

b0r3d0m
()

&add_num это указатель на указатель на функцию, пиши p = add_num;

Ибо имя функции приводится к типу указателя на функцию. Примерно как массив приводится к указателю при передаче в функцию.

Тему не читал

Deleted
()
Ответ на: комментарий от Kronick

если бы знал как, я вообще думал что это какая-то мифическая фигура и он сам материализуется когда нужен, так вот час настал, а его все нет и нет

Царь живет в удаленных и вылазит на свет или случайно, или по недосмотру модераторов.

Pavval ★★★★★
()

Обычно достаточно (void*)
Generic pointer можно любому указателю присваивать. Спасает, когда много таких присвоений и сигнатуры раздувают код.

mittorn ★★★★★
()
Последнее исправление: mittorn (всего исправлений: 1)

Всем спасибо, в этом разобрался. Как же хорошо когда есть у кого такое спросить

Kronick
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.