Замена нескольких символов одновременно - PullRequest
2 голосов
/ 27 июля 2011

Итак, в моем коде есть ряд символов, которые я хочу заменить случайными данными. Поскольку rand может заменить целые числа, я решил сэкономить немного времени, заменив четыре символа одновременно вместо одного. Так что в основном вместо этого:

  unsigned char TXT[] = { data1,data2,data3,data4,data4,data5....
  for (i = 34; i < flenght; i++) // generating the data to send.
     TXT[i] = rand() % 255;

Я бы хотел сделать что-то вроде:

unsigned char TXT[] = { data1,data2,data3,data4,data4,data5....
for (i = 34; i < flenght; i+4) // generating the data to send.
  TXT[i] = rand() % 4294967295;

Что-то такое, но я не уверен, как сделать последнюю часть. Любая помощь, которую вы можете мне оказать, очень ценится, спасибо!

Ответы [ 7 ]

3 голосов
/ 27 июля 2011

Это не сработает.Компилятор возьмет результат из rand() % big_number и отрежет дополнительные данные, чтобы они соответствовали unsigned char.

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

То, что вы хотели сделать , возможно, возможно, но, учитывая вашу ошибку, я бы сказал, что попытка понять, насколько прямо сейчас далекоперевешивает преимущества.Продолжайте учиться, и в следующий раз, когда вы столкнетесь с таким кодом, вы будете знать, что делать (и судите, если это необходимо), посмотрите на этот момент и улыбнитесь:).

0 голосов
/ 27 июля 2011

1) % означает «остаток от деления на», поэтому вы хотите rand() % 256 для символа, иначе вы никогда не получите символы со значением 255. Аналогично для случая int, хотя здесь естьв любом случае нет смысла выполнять операцию модуля, поскольку вам нужен весь диапазон выходных значений.

2) rand обычно генерирует только два байта за раз;проверьте значение RAND_MAX.

3) 34 не делится на 4 в любом случае, поэтому вам придется обрабатывать конечный регистр специально.

4) Вы захотите привести указатель,и он не будет работать, если он еще не выровнен.Однако после того, как у вас есть приведение, нет необходимости учитывать sizeof(int) в вашей итерации: арифметика указателя автоматически заботится о размере элемента.

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

0 голосов
/ 27 июля 2011

Это не работает, потому что сгенерированное значение преобразуется в тип элемента массива - char в данном конкретном случае. Но вы можете интерпретировать выделенную память так, как вам нравится. Например, вы можете преобразовать его в массив int:

unsigned char TXT[] = { data1,data2,data3,data4,data4,data5....
for (i = 34; i < flenght-sizeof(int); i+=sizeof(int)) // generating the data to send.
    *(int*)(TXT+i) = rand(); // There is no need in modulo operator
for (; i < flenght; ++i) // generating the data to send.
    TXT[i] = rand(); // There is no need in modulo operator either

Я просто хочу завершить решение замечаниями об операторе по модулю и обработке массивов, не кратных sizeof(int).

0 голосов
/ 27 июля 2011

Есть правильные ответы, но C не очень заботится о том, какой тип он хранит по какому адресу. Так что вы можете получить что-то вроде:

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


char *arr;
int *iArr;


int main (void){
  int i;
  arr = malloc(100);
  /* Error handling ommitted, yes that's evil */
  iArr = (int*) arr;

  for (i = 0; i < 25; i++) {
   iArr[i] = rand() % INT_MAX;
  }

  for (i = 0; i < 25; i++) {
   printf("iArr[%d] = %d\n", i, iArr[i]);
 }

for (i  = 0; i < 100; i++) {
  printf("arr[%d] = %c\n", i, arr[i]);
}
free(arr);
return 0;
}

В конце концов, массив - это просто непрерывный блок в памяти. И вы можете интерпретировать это как хотите (если хотите). Если вы знаете, что sizeof (int) = 4 * sizeof (char), то приведенный выше код будет работать.

Я не говорю, что рекомендую это. А остальные указали на то, что бы ни случилось, первый цикл через все символы в TXT даст тот же результат. Можно подумать, например, о развертывании цикла, но на самом деле мне было бы все равно.

(int *) только один достаточно предупреждающий. Для компилятора это означает, что не думайте о том, что, по вашему мнению, тип просто «верит» программисту, который знает лучше.

Ну, это "знай лучше", вероятно, является корнем всего зла в программировании на Си ....

0 голосов
/ 27 июля 2011
unsigned char TXT[] = { data1,data2,data3,data4,data4,data5....
for (i = 34; i < flenght; i+4)
    // generating the data to send.
    TXT[i] = rand() % 4294967295;

У этого есть несколько проблем:

  • TXT не гарантированно выровнен по памяти, как это требуется для CPU для записи int данных (работает ли это - возможно, относительно медленно -или нет - например, SIGBUS на Solaris - зависит от аппаратного обеспечения)
  • последние 1-3 символа могут быть пропущены (даже если вы измените i + 4 на i += 4 ;-P)
  • rand() возвращает int в любом случае - вам не нужно модифицировать его с чем-либо
  • , вам нужно записать свои случайные данные с помощью int*, чтобы вы получали доступ к 4 байтам за раз, а не простовырезая байт из конца случайных данных и перезаписывая каждый четвертый отдельный символ
  • для подобных вещей, когда вы зависите от размера int, вы должны написать это в терминах sizeof(int)так что он будет работать, даже если int не 32-битный, или использовать (в настоящее время, к сожалению) нестандартный, но общий typedef, такой как int32_t (или в Windows, я думаю, что это __int32, или вы можете использовать boost или другой заголовок библиотеки, чтобы получить int32_t, или написать свой typedef).

На самом деле довольно сложно выровнять ваши текстовые данные: ваш код предполагает, что вы хотите использовать срезы размером int для 35-го символа ... даже если весь массив символов правильно выровнен для целых, 35-й символ не будетbe.

Если он действительно всегда 35-й, то вы можете заполнить данные начальным символом, чтобы получить доступ к 36-му (кратному, предположительно, 32-битному int размеру), а затем выровнятьтекст на 32-битный адрес (с указанием компилятора #pragma или с использованием объединения с int32_t).Если реальный код изменяет символ, с которого вы начинаете перезаписывать, так что вы не можете просто выровнять данные один раз, то вы застряли с:

  • ваших исходных перезаписываемых символов за раз
  • непереносимые невыровненные перезаписи (если это возможно и лучше в вашей системе), ИЛИ
  • реализация кода, который перезаписывает до трех ведущих невыровненных символов, затем переключается в 32-разрядный целочисленный режим перезаписивыровненные адреса, затем обратно к посимвольной перезаписи до трех завершающих символов.
0 голосов
/ 27 июля 2011
 TXT[i] = rand() % 4294967295;

Не будет работать так, как вы ожидаете. Возможно, вы ожидаете, что rand()%4294967295 сгенерирует 4-байтовое целое число (которое вы можете интерпретировать как 4 разных символа). Значение, которое выдает rand()%4294967295, будет приведено к типу в виде одного символа и будет присвоено только одному из индексов TXT[i].

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

0 голосов
/ 27 июля 2011

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

unsigned char TXT[] = { data1,data2,data3,data4,data4,data5....
for (i = 34; i < flenght/sizeof(int); i+=sizeof(int)) // generating the data to send.
{
     int *temp = (int*)&TXT[i]; // very ugly
     *temp = rand() % 4294967295;
}

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

...