Как несколько переменных могут быть переданы в функцию чисто в C? - PullRequest
6 голосов
/ 13 апреля 2010

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

Мне не нужно передавать ВСЕ из них слишком часто, но я надеялся получить функцию, которая будет считывать входные данные (в данном случае из сети TCP), а затем анализировать данные (IE, 3-й Байт содержит состояния 8 цифровых выходов (в соответствии с тем, какой бит в этом байте является старшим или младшим) и помещает его в переменную, которую я затем могу использовать в другом месте программы.

Я хотел, чтобы эта функция была отделена от функции main (), но для этого потребовалось бы передать указатели примерно на 20 или около того переменных, в которые она будет записывать. Я знаю, что могу сделать переменные глобальными, но я пытаюсь упростить отладку, сделав это очевидным, когда функции разрешено редактировать эту переменную, передав ее функции.

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

Так или иначе, есть ли чистый способ посылки сразу нескольких переменных между функциями, которые необходимо отредактировать?

Ответы [ 5 ]

6 голосов
/ 13 апреля 2010

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

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

typedef struct a {
  struct b {
    int b1;
    int b2;
  } b_s;
  struct c {
    int c1;
    int c2;
  } c_s;
} a_s;
3 голосов
/ 13 апреля 2010

Это классическое использование «блока параметров» - просто указатель на хорошо известную структуру.

Преимущества: Эффективность, поскольку любой доступ к данному параметру является адресом плюс смещение; Простота отладки (вы можете увидеть все параметры в одной «печати»); Местность (хорошо кэшируется); Легко превратить в набор стеков вызовов, где вы не можете точно знать, какие параметры могут понадобиться для любой данной функции в стеке.

Недостатки: Вы не можете сказать, глядя на вызов функции , какие параметры важны для вызываемого абонента - вы должны знать или копаться в источнике этой функции; Побочные эффекты легче вызывать, особенно если вы разрешаете вызываемым функциям изменять блок (плохо, плохо, плохо!); Увеличивает связь (каждая функция может видеть каждый параметр, который может привести к искушениям ...)

0 голосов
/ 13 апреля 2010

Передача указателя на структуру обычно является "чистым" способом. Интеллектуальное определение структуры данных может дать этому методу как мощность, так и гибкость. Например возьмем структуру данных:

struct func_params {
    int type;
    union {
        struct {
            int    port;
            int    direction;
            long   target_addr;
        } digital_io;
        struct {
            int    channel;
            long   sample_rate;
        } analog_in;
        struct {
            int    channel;
            int    async;
            int    hold_output;
        } analog_out;
        struct {
            int    port;
            int    direction;
            int    encoding;
        } serial_io;
    };
};

Определите вашу функцию с помощью чего-то вроде

my_function (struct func_params* pStruct, size_t length)

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

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

0 голосов
/ 13 апреля 2010

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

0 голосов
/ 13 апреля 2010

Я бы сказал, что структура - ваш лучший выбор. Вы можете передать только один из членов функции, если вам не нужны все переменные в определенной функции. Вы также можете воспользоваться битовым полем для этого 3-го байта, если вам нужно установить отдельные биты. Конечно, это битовое поле также может быть членом вашей структуры.

...