Как создать общий указатель, который может работать с переменными типа int и double и избежать проблем с областями видимости?

0

У меня есть код C, где мне нужно делать некоторые вычисления с массивом данных. Данные могут быть либо INT, либо DOUBLE. Чтобы иметь дело с разными типами данных, я думал использовать оператор if/else и определять указатель, содержащий данные внутри этого оператора:

/* put values into M, depending on data type*/
if (data_type == 2)
{
    double *M;  
    M = somefunction(DOUBLE);
} else {
    unsigned int *M;
    M = somefunction(UINT16);
}

/* dummy code - usually I do some calculations on M which are data type independent */
for (i=0;i<(10);i++) {
    M[i]=0;
}

Это приводит к проблемным задачам, поскольку M не определяется вне конструкции if/else:

 error: ‘M undeclared (first use in this function)

Если я двигаю определение M вне if/else выражение, код скомпилируется, но M внутри if/else является другой M снаружи.

Поэтому я могу обойти проблему, указав два указателя, один двойной и один int и проверим всюду в моем коде, с которым я имею дело:

double *Mdouble;  
unsigned int *Mint;
/* put values into M, depending on data type*/
if (data_type == 2)
{
    Mdouble = somefunction(DOUBLE);
} else {
    Mint = somefunction(UINT16);
}

/* dummy code - usually I do some calculations on M which are data type independent */
for (i=0;i<(10);i++) {
    if (data_type == 2) {
        Mdouble[i]=0;
    } else {
        Mint[i]=0;
    } 
}

Итак, вот мой вопрос:

Как я могу решить эту проблему, когда M является двойным или int, в зависимости от моих входящих данных? Могу ли я решить это с помощью какого-то указателя на работу указателя? Я не хочу писать дубликат кода для каждого случая.

EDIT может создавать шаблонные функции или перегружать функции, решая мою проблему? Я гибко отношусь к конкретному решению C/C++

  • 2
    Похоже, вы собираетесь изобретать дискриминационные союзы.
  • 1
    С C ++ (удаленный тег) у вас может быть somefunction шаблона, которая может решить вашу проблему.
Показать ещё 10 комментариев
Теги:
pointers

5 ответов

3

Вам придется писать дубликат кода.

На базовом уровне требуемый машинный код для добавления двух чисел отличается для целых чисел и чисел с плавающей запятой.

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

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

  • 0
    функция шаблона решит мою проблему?
  • 0
    @ memyself с шаблонами, вы можете отделить алгоритм от типа данных, вероятно, лучше всего, если вы гуглите после шаблона c ++ - потому что это многое объясняет.
Показать ещё 2 комментария
2

Вы можете попробовать использовать C-соединение:

#include <string.h>
#include <stdio.h>

int main(int argc, char** argv) {
  union MyUnion {
    int I;
    double D;
  };
  union MyUnion M[10];
  // Initializing the array to 0 (data type independent)
  memset(M, 0, 10*sizeof(MyUnion));
  M[0].I = 1;
  M[1].D = 1.5;
  if (argc==1) { // It should be "if (data_type==2) {"
                 // but I wanted an example that compiles easily
    printf("%i\n", M[0].I); //somefunction(M[0].I);
  } else {
    printf("%lf\n", M[1].D); //somefunction(M[1].D);
  }
}
  • 0
    не могли бы вы уточнить этот пример и, возможно, связать его с моим примером выше? Я не вижу связи сейчас. Спасибо!
  • 0
    Я только что отредактировал код, чтобы добавить несколько комментариев. Я хочу сказать, что вы можете использовать союзы, чтобы интерпретировать одни и те же данные по-разному. Но я думаю, что это не решит вашу проблему, если вам нужно сделать арифметическую операцию независимой от типа данных.
1

В C вам нужно будет использовать макрос

int8_t* ptr=...;
while(n)
    {
    switch(data_type)
        {
        case TYPE_DOUBLE:
            A_MACRO_THAT_DEFINES_YOUR_OPERATION((double*)ptr);
            ptr+=sizeof(double);
            break;
        case TYPE_INT:
            A_MACRO_THAT_DEFINES_YOUR_OPERATION((int*)ptr);
            ptr+=sizeof(int);
            break;
        }
    --n;
    }

Это решение выполняется медленно, так как для каждого элемента необходимо проверить тип данных. Вместо этого вы можете написать весь цикл как макрос. Это будет быстрее, но сложнее читать.

Если вы можете использовать C++, используйте вместо этого шаблон. Вот решение с использованием шаблонов:

template<class T>
void doStuff(T* ptr_begin,T* end)
    {
    while(ptr_begin!=ptr_end)
        {
   //   Do stuff
        ++ptr_begin;
        }
    }

void doStuffWrapper(void* ptr_begin,void* ptr_end,uint32_t type)
    {
    switch(type)
        {
        case TYPE_DOUBLE:
            doStuff((double*)ptr_begin,(double*)ptr_end);
            break;
        case TYPE_INT:
            doStuff((int*)ptr_begin,(int*)ptr_end);
            break;
        }
    }

В качестве побочного примечания: в этом случае я предпочитаю switch-case over if-else, так как он легче поддерживать и может генерировать более быстрый код.

0

Похоже, вы хотите использовать шаблонную функцию.

Но я думаю, что вопрос сводится к тому, что вы можете поместить всю свою работу в эту функцию?

template <typename T>
T* somefunction(T data){
    //start old somefunction code
    T* result = new T[10]{data, data, data, data, data, data, data, data, data, data};
    //end old somefunction code

    //begin "calculations on M which are data type independent"
    for(int i = 0; i < 10; i++){
        M[i] = 0;
    }
    return M;
}

Таким образом, с приведенным выше кодом вы можете сделать либо double* Mdouble = somefunction(13.13) либо short* Mshort = somefunction(13);

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

0

Вы можете использовать макрос, например:

#define CALCULATIONS(M) do { \
    for (i=0;i<(10);i++) \
        (M)[i]=0; \
    } while (0)

а затем в другом коде:

if ( data_type == 2 )
{
    double *M = whatever;
    CALCULATIONS(M);
}

Смотрите здесь, если вы не знакомы с do...while(0)

  • 0
    почему часть while (0) необходима? { отсутствует в строке 2?
  • 0
    Да, исправил недостающую скобку спасибо
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню