C Пустой указатель вопрос - PullRequest
5 голосов
/ 08 июля 2010

У меня есть функция grep в C (встроенное программирование), которая принимает пустой указатель в качестве параметра. функция должна иметь возможность обрабатывать различные типы переменных, такие как chars int и long. Как я могу кодировать функцию, чтобы она сама могла определить, какой тип переменной я передаю ?? Я не знаю, возможно ли это. спасибо

т.


void grep( void *t ) 
{ 
   if( t == char ) 
   { 
      do this 
   } 
   if( t == int ) 
   { 
      do that  
   }  
   ... 
}

Ответы [ 12 ]

14 голосов
/ 08 июля 2010

Это невозможно сделать с какой-либо точностью.Например, 4-байтовое целое может быть легко интерпретировано как строка.Например, строка с нулевым окончанием «ABC» будет такой же, как целочисленное значение 1094861568 (в зависимости от порядка байтов).

6 голосов
/ 08 июля 2010

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

Если вы можете использовать C ++, вы можете создать набор перегруженных вспомогательных функций, которые будут предоставлять информацию о типе.

5 голосов
/ 08 июля 2010

Это невозможно в C. Вам нужно будет явно указать предполагаемый тип параметра. Вам нужно будет передать второй аргумент или передать объединение или структуру, которая имеет информацию о типе в качестве параметра.

3 голосов
/ 08 июля 2010

Прямой ответ: это невозможно. Кроме того, вам следует избегать написания таких суперфункций, которые работают с несколькими типами, если только вы не сможете по-настоящему обобщить код и применить полиморфизм. В Си это часто связано с указателями на функции. В противном случае нет ничего плохого в написании нескольких функций, каждая из которых действует на один тип. На самом деле, это должно быть предпочтительнее суперфункций.

Вот базовый пример (не очень полезный, но простой):

#include <stdio.h>

typedef int less_function(void*, void*);

struct foo
{
    int data;
};

int foo_less(void* a, void* b)
{
    struct foo* f1 = a;
    struct foo* f2 = b;
    return f1->data < f2->data;
}

int find(void* search_array, void* element, int num, int element_size, less_function* less)
{
    int j = 0;
    char* search_pos = search_array;

    for (j=0; j < num; ++j, search_pos += element_size)
    {
        // if current element == element to find
        if (!less(search_pos, element) && !less(element, search_pos) )
            return j;
    }
    return -1;
}

int main()
{
    struct foo my_array[10] = { {0}, {1}, {2}, {3}, {4}, {5}, {6}, {123}, {7}, {8} };
    struct foo search_element = {123};

    // outputs 7
    printf("%d\n", find(my_array, &search_element, 10, sizeof(struct foo), foo_less) );
}

В приведенном выше коде вы можете видеть, что у меня нет такого кода: если этот тип является целым числом, сделайте это, если это число с плавающей запятой, сделайте это, если это объект struct foo, сделайте это и т. Д. Вместо этого мы полагаемся на указатели на функции, чтобы обеспечить настраиваемое поведение для сравнения типа передаваемого объекта.

qsort также делает это и является хорошим примером для рассмотрения. Она очень похожа на функцию поиска выше, за исключением того, что ее компаратор не просто возвращает истину / ложь, основываясь на том, меньше ли первый объект, чем другой: он похож на strcmp и возвращает 0, -1 или + 1.

3 голосов
/ 08 июля 2010

Вы в основном спрашиваете, как сделать самоанализ в C. К сожалению, эта функция не поддерживается.

Вместо этого вы можете использовать такие функции, как grep_char, как указано @ anand.arumug. Или (если возможно) вы можете перейти на C ++ и использовать функции перегрузки функций.

2 голосов
/ 08 июля 2010

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

2 голосов
/ 08 июля 2010

Я думаю, вы обнаружите, что это невозможно в C.

C ++ имеет шаблоны и перегрузки, которые являются хорошим решением для такого рода проблем.

В простом старом C вы просто пишете разные функции для каждого типа, с которым вам нужно работать.

Макросы являются еще одним вариантом в C, но подумайте, стоит ли их усилий и путаницы, которые могут вызвать другие разработчики.

1 голос
/ 08 июля 2010

Нет, это невозможно.

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

Перечисления будут проще, если вы передадите любой другой тип данных позже.Вы можете использовать оператор switch внутри функции и выполнять операции с входными данными.

enum TYPE( TYPE_1, TYPE_2, TYPE_3,TYPE_MAX}; /*Add other data types into this enum if need be */

Пожалуйста, назовите записи enum согласно вашему требованию.

Позже вы можете просто изменить функциюпереключите регистр и добавьте к нему дополнительный регистр.

1 голос
/ 08 июля 2010

Этот тип многоцелевой функции не рекомендуется, так как трудно отлавливать ошибки программирования и отлаживать их. Я предлагаю создать отдельные функции grep для каждого типа аргумента и иметь эти вспомогательные функции вызова для любой общей логики кода grep.

Если вы должны передать функции без типов в функции, то я предлагаю вам обернуть их в структуру, которая украшает их типом. Что-то вроде:

struct {
    enum TYPE { INT, CHAR, STRING } type;
    void *object;
}
1 голос
/ 08 июля 2010

Единственный способ, о котором я могу думать, это либо передать тип в качестве второго параметра, либо создать структуру с указателем и перечислением или чем-то, определяющим тип, и передать его вместо пустого указателя.C не имеет встроенных метаданных, как .net и Java, или даже эквивалент RTTI, о котором я знаю.

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