开发者

Replacing multiple chars at the same time

So in my code I have a series of chars which I want to replace with random data. Since rand can replace ints, I figured I could save some time by replacing four chars at once instead of one at a time. So basically instead of this:

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

I'd like to do something like:

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

Something that effect, but I'm not sure how to do the latter part. Any help you can give me is greatly appreciated, thanks!


That won't work. The compiler will take the result from rand() % big_number and chop off the extra data to fit it in an unsigned char.

Speed-wise, your initial approach was fine. The optimization you contemplated is valid, but most likely unneeded. It probably wouldn't make a noticeable difference.

What you wanted to do is possible, of course, but given your mistake, I'd say the effort to understand how right now far outweights the benefits. Keep learning, and the next time you run across code like this, you'll know what to do (and judge if it's necessary), look back on this moment and smile :).


You'll have to access memory directly, and do some transformations on your data. You probably want something like this:

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;
}

It can be problematic though because of alignment issues, so be careful. Alignment issues can cause your program to crash unexpectedly, and are hard to debug. I wouldn't do this if I were you, your initial code is just fine.


 TXT[i] = rand() % 4294967295;

Will not work the way you expect it to. Perhaps you are expecting that rand()%4294967295 will generate a 4 byte integer(which you maybe interpreting as 4 different characters). The value that rand()%4294967295, produces will be type cast into a single char and will get assigned to only one of the index of TXT[i].

Though it's not quire clear as to why you need to make 4 assigning at the same time, one approach would be to use bit operators to obtain 4 different significant bytes of the number generated and those can then be assigned to the four different index.


There are valid answers just so much C does not care very much about what type it stores at which address. So you can get away with something like:

#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;
}

In the end an array is just some contiguous block in memory. And you can interpret it as you like (if you want). If you know that sizeof(int) = 4 * sizeof(char) then the above code will work.

I do not say I recommend it. And the others have pointed out whatever happened the first loop through all the chars in TXT will yield the same result. One could think for example of unrolling a loop but really I'd not care about that.

The (int*) just alone is warning enough. It means to the compiler, do not think about what you think the type is just "believe" he programmer that he knows better.

Well this "know better" is probably the root of all evil in C programming....


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;

This has a few issues:

  • TXT is not guaranteed to be memory-aligned as needed for the CPU to write int data (whether it works - perhaps relatively slowly - or not - e.g. SIGBUS on Solaris - is hardware specific)
  • the last 1-3 characters may be missed (even if you change i + 4 to i += 4 ;-P)
  • rand() returns an int anyway - you don't need to mod it with anything
  • you need to write your random data via an int* so you're accessing 4 bytes at a time and not simply slicing a byte off the end of the random data and overwriting every fourth single character
  • for stuff like this where you're dependent on the size of int, you should really write it in terms of sizeof(int) so it'll work even if int isn't 32 bits, or use a (currently sadly) non-Standard but common typedef such as int32_t (or on Windows I think it's __int32, or you can use a boost or other library header to get int32_t, or write your own typedef).

It's actually pretty tricky to align your text data: your code suggests you want int-sized slices from the 35th character... even if the overall character array is aligned properly for ints, the 35th character will not be.

If it really is always the 35th, then you can pad the data with a leading character so you're accessing the 36th (being a multiple of presumably 32-bit int size), then align the text to an 32-bit address (with a compiler-specific #pragma or using a union with int32_t). If the real code varies the character you start overwriting from, such that you can't simply align the data once, then you're stuck with:

  • your original character-at-a-time overwrites
  • non-portable unaligned overwrites (if that's possible and better on your system), OR
  • implementing code that overwrites up to three leading unaligned characters, then switches to 32-bit integer overwrite mode for aligned addresses, then back to character-by-character overwrites for up to three trailing characters.


That does not work because the generated value is converted to type of array element - char in this particular case. But you are free to interpret allocated memory in the manner you like. For example, you could convert it into array 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

I just want to complete solution with the remarks about modulo operator and handling of arrays not multiple of sizeof(int).


1) % means "the remainder when divided by", so you want rand() % 256 for a char, or else you will never get chars with a value of 255. Similarly for the int case, although here there is no point in doing a modulus operation anyway, since you want the entire range of output values.

2) rand usually only generates two bytes at a time; check the value of RAND_MAX.

3) 34 isn't divisible by 4 anyway, so you will have to handle the end case specially.

4) You will want to cast the pointer, and it won't work if it isn't already aligned. Once you have the cast, though, there is no need to account for the sizeof(int) in your iteration: pointer arithmetic automatically takes care of the element size.

5) Chances are very good that it won't make a noticeable difference. If scribbling random data into an array is really the bottleneck in your program, then it isn't really doing anything significiant anyway.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜