Как я могу улучшить читаемость кода?

#c #winsock

#c #winsock

Вопрос:

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

 send(socket, FIXED_VALUE_N, (int)strnlen(FIXED_VALUE), 0);
  

В то же время было бы удобно для удобочитаемости и удобства настройки пар (имя, значение) таким или аналогичным образом (считайте это псевдокодом):

 FIXED_VALUE_1 <- 1
FIXED_VALUE_2 <- 2
FIXED_VALUE_3 <- 3
...
  

Для чего я могу использовать? Я отбросил перечисления, поскольку они являются целыми числами, и я считаю пустой тратой времени на четыре отправки по одному байту каждая. Альтернативой было бы определить макрос, но я не могу определить макрос для байта, а не только для строки, поскольку я хочу отправить ’27’, а не ‘2’,’7′.

Заранее спасибо.

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

1. Я думаю, что этот стек более подходит: codereview.stackexchange.com

2. Рассматривали ли вы возможность объединения строк ваших данных в группы, разделенные запятыми? Это позволило бы отправлять несколько пар и анализировать их на принимающей стороне.

3. Хм. strnlen требуется два аргумента, просто предупреждаю.

4. Вы также можете написать макрос, чтобы превратить ваш номер в кавычки.

5. Что-то вроде #define FIXED_VALUE_N "123" ? Разве это не строка из 3 байт?

Ответ №1:

Во-первых, обратите внимание, что, как написано,

 send(socket, FIXED_VALUE_N, (int)strnlen(FIXED_VALUE_N), 0);  
                                                    ^^ //added to correct typo
  

FIXED_VALUE_N должно быть в форме const char *, чтобы быть правильным. И, strnlen() требуется два аргумента, (второй — size_t number_of_elements ).

РЕДАКТИРОВАТЬ 3 (обращаясь к последнему вопросу комментария)

Если вы объявите и заполните FIXED_VALUE_N как:

 const char FIXED_VALUE_N[2];
FIXED_VALUE_N[0]=0x1B;  
  

А также исправить синтаксис третьего аргумента…

 send(socket, FIXED_VALUE_N, 1, 0); //hard-coded third argument for illustration  
  

… Это сработает, потому что теперь вы передаете указатель на const char ( const char * ) во втором аргументе и соответствуете синтаксическим требованиям send() прототипа.
(окончательная ПРАВКА 3)

Имея это в виду, рассматривали ли вы объединение строк данных в группы, разделенные запятыми? Это позволило бы отправлять несколько значений и анализировать их на принимающей стороне. Что-то вроде:

 #define MAX_SIZE 100 //pick a value that makes sense for your application, I randomly picked 100
char buffer[MAX_SIZE];
int len=0;

sprintf(buffer, "%d,%d,%d", FIXED_VALUE_1, FIXED_VALUE_2,FIXED_VALUE_3);
len = strlen(buffer); //****
send(socket, buffer, len   1, 0);  // strlen() does not include `` byte in its return
                                   // value.  Use `len  1` to make room for 
                                   //  terminator - added by the sprintf() function.
  

Отправил бы "1,2,3"

Что касается вашего заявления: поскольку я хочу отправить ’27’, а не ‘2’, ‘7’.

Не используйте запятые в инструкции форматирования sprintf() , и отправленные вами числа будут последовательными.

 sprintf(buffer, "%d%d%d", FIXED_VALUE_1, FIXED_VALUE_2,FIXED_VALUE_3);
                 ^^^^^^  
  

Отправил бы "123"

РЕДАКТИРОВАТЬ (заполнить len, используя возврат sprintf)
Также, как указал @Jack:
Вместо использования strlen() вы можете сохранить строку кода, просто установив len = sprintf(…); в строке выше. (см. **** Фрагмент кода выше) as sprintf() возвращает количество переданных символов или отрицательное значение, если произошла ошибка вывода. (если результат отрицательный, произошла ошибка)

ОТРЕДАКТИРУЙТЕ 2 (байтовые данные, согласно вашему комментарию выше)

Если вы хотите отправлять данные в наименьшем (наиболее эффективном) форм-факторе, используйте байтовые данные. байтовые данные могут храниться в массиве символов:

 char *byte_data=0;

byte_data = malloc(NUM_BYTES_RQD);//#define NUM_BYTES_RQD as needed, 
                                  //or pass in size info as an argument 
                                  //from calling function  

//populate byte_data

for(i=0;<NUM_BYTES_RQD;i  )
{
    byte_data[i]=<enter byte value here>
}
send(socket, byte_data, len, 0);  
free(byte_data);
  

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

1. sprintf() верните количество байтов, записанных в буфер, чтобы вы могли использовать его вместо strlen(buffer)

2. Моя точка зрения заключалась не только в сохранении строки кода, но и в производительности. Если вы можете избежать вычисления одного и того же значения дважды (или в режиме), вам не следует этого делать.

3. @Джек — согласен. Увеличение производительности предполагалось за счет сохранения строки кода 🙂

4. Не отправляя '' , как получающая сторона узнает, когда заканчивается содержимое одного send() и начинается другое? Подумайте send(socket, buffer, len 1, 0); или допишите запятую.

5. @chux — Спасибо. Добавил это и прокомментировал. Но важно отметить: методы recv() сильно различаются в зависимости от реализации протоколов, использующих их. Я использовал протоколы, в которых определенная серия байтов указывала на конец блока данных. Поэтому я не думаю, что всегда необходимо включать для завершения байтовых данных.

Ответ №2:

Рассматривали ли вы возможность использования макроса X?

 #define X(a, b) a,

#define FIXED_VALUES_TABLE
X(FIXED_VALUE_1, "1") 
X(FIXED_VALUE_2, "2") 
// ...

enum { FIXED_VALUES_TABLE };
#undef x

#define X(a, b) b,
const char *fixed_values_values[] = { FIXED_VALUES_TABLE };
#undef x
  

И тогда вы можете использовать вот так:

 char *val = fixed_values_values[FIXED_VALUE_1];
char *va2 = fixed_values_values[FIXED_VALUE_2];
  

если вы хотите объединить их, вы можете использовать malloc() strcat() .

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

1. Я не слышал об этом. Очень приятно.