I have 2 array: the first one is 8 unsigned char, and the second one is 4 unsigned short, for some algorithm compatibility issue i need to use the short array with the values of the char array, to do so i'm doing a loop
j = 0;
for(i=0; i<8; i+=2)
{
short_array[j] = *(unsigned short*) (char_array + i);
j++;
}
Everything work fine here, but in some previous attempt to build this up, i've tried the following (this is obviously not the correct answer)
j = 0;
for(i=0; i<8; i+=2)
{
short_array[j] = (unsigned short*) *(&(char_array + i));
j++;
}
QUESTION:
Assuming the following char_array = {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88}
When I do the first one short_array = {0x1122, 0x3344, 0x5566, 0x7788}
But when I do the second one, short_array = {0x3344, 0x5566, 0x7788, ???} (where ??? is undefined since it is a value in the memory and may change).
Can you explain why this i happening?
PS: My compiler suite is C251 from Keil
I've compared the 2 solutions (even if the second is not a working one), and this is definitly a compiler issue, first of all the compiler shouldn't let me compile &(char_array + i) , then I've find out (when inspecting the assembly code) that the char_array is incremented before accessing it in the loop for the second case; and the increment is made after reading the variable in the first case (the correct one). There seem to be no more explanation than a compiler implementation problem...
I would suggest to manually read out each element in your char array and build each pair of chars into a short. I know that there are probably faster methods, but you are implicitly stepping over the bounds of the type you have specific in the char array otherwise. Also, I would claim that my version is slightly easier to read in terms of your intent, albeit more kludgy.
That is, something like this:
IGNORE THIS FIRST CODE BLOCK... THIS IS WHAT HAPPENS WHEN I DON'T SLEEP!
j=0;
uint16_t temp; // recommend to use these types for portability
for(i=0; i<8; i+=2) {
temp = 0x0000;
temp += (uint16_t)(char_array[i] << 8);
temp += (uint16_t)(char_array[i+1]);
short_array[j] = temp;
j++;
}
Also, here's a faster method I came up with after thinking about the problem a bit more, and giving myself a well-deserved self-imposed code review.
j=0;
for(i=0; i<8; i+=2) {
short_array[j] = (char_array[i] << 8) | char_array[i+1]; // use bitwise operations
j++;
}
Related
I have read this post on how to fuse a loop. The goal is to fuse my double for loop in order to parallelize it with OpenMP. The reason why I don't use collapse(2) is because the inner loop has dependencies on the outer one. I have also read this relevant post.
My problem though, is that when I fuse my loop I get a Segmentation Fault error and that sounds pretty fuzzy. I am pretty sure I am making the right conversion. Unfortunately there is no way I can provide a reproducible - minimal example as my program has a ton of functions where they call one another. Here is my initial loop though:
for(int i=0; i<size; i++)
{
int counter = 0;
for(int j=0; j<size; j++)
{
if (i==j)
continue;
if(arr[size * i + j])
{
graph->nodes[i]->degree++;
graph->nodes[i]->neighbours[counter] = (Node*)malloc(sizeof(Node));
graph->nodes[i]->neighbours[counter] = graph->nodes[j];
counter++;
}
}
}
where graph is a pointer to Struct and graph->nodes is an array of pointers to the graph's nodes. Same goes for graph->nodes[i]->neighbours. An array of pointers (pointed to by a pointer pointed to by another pointer - sorry).
As you can see the fact that I am using the counter variablethat restricts me from using #pragma omp parallel for collapse(2). Below you can see my converted loop:
for(int n=0; n<size*size; n++)
{
int i = n / size;
int j = n % size;
int counter = 0;
for(int j=0; j<size; j++)
{
if (i==j)
continue;
if(arr[size * i + j])
{
graph->nodes[i]->degree++;
graph->nodes[i]->neighbours[counter] = (Node*)malloc(sizeof(Node));
graph->nodes[i]->neighbours[counter] = graph->nodes[j];
counter++;
}
}
}
I have tried debugging with valgrind and what's ultra weird is that the Segmentation Fault does not appear to be on these specific lines, although it happens only when I make the loop conversion.
Mini disclaimer: As you may guess, because of these pointer to pointer to pointer variables I use lots of mallocs.
I don't expect you to get the same error with the code that I have posted that is why my question is more of a general one: How could theoretically a loop fusion cause a segfault error?
I think in your converted loop you got i and j mixed up.
It should be int i = n % size;, not j.
n / size always equals 0.
I currently have a simple program that sets up a framebuffer that can be written to.
I am encountering behaviour where values stored i arrays, once retrieved, come back as seemingly random values, with no relation to the originals.
I have also noticed some similarly strange and.unexpected behaviour from switch statements - I suspect this has something to do with how both arrays and switch statements are statically allocated in memory.
As an example, here I have some code that should draw a hardcoded number, followed by 7 other hardcoded numbers that have been stored in an array:
unsigned int cols[7] = { 0xFFFF0000, 0xFFFF7F00, 0xFFFFFF00, 0xFF00FF00, 0xFF0000FF, 0xFF4B0082, 0xFF9400D3 };
drawNum(&display, 0x1234ABCD);
for (int i=0; i<7; i++)
drawNum(&display, cols[i]);
The first drawNum() call with the hardcoded value works fine, but all of the calls with array accesses give seemingly random results.
Assigning the array values at runtime doesn't have this problem, like so:
unsigned int cols[7];
cols[0] = 0xFFFF0000;
cols[1] = 0xFFFF7F00;
cols[2] = 0xFFFFFF00;
cols[3] = 0xFF00FF00;
cols[4] = 0xFF0000FF;
cols[5] = 0xFF4B0082;
cols[6] = 0xFF9400D3;
drawNum(&display, 0x1234ABCD);
drawNum(&display, (int)cols);
for (int i=0; i<7; i++)
drawNum(&display, cols[i]);
I've also experienced similarly unpredictable behaviour when returning values from switch statements.
I cannot say for sure, but this leads me to believe that this is a problem with the compiler or linker being used - I am using arm-none-eabi.
Just a shot in the dark, but you may want to try a different value in your array where the highest bit is 0 instead of 1 like in your hardcoded example.
unsigned int cols[7] = { 0x7FFF0000, 0x7FFF7F00, 0x7FFFFF00, 0x7F00FF00, 0x7F0000FF, 0x7F4B0082, 0x7F9400D3 };
This is assuming that drawNum takes an int instead of an unsigned int. You might just have a conversion problem. Without seeing what drawNum does it's hard to say.
And here my shot in the dark. You have a memory overwrite anywhere and this kills cols[]. If you move the variable from global scope to local scope the outcome varies. Add some 'detector' code:
volatile unsigned int cols[7] = { 0xFFFF0000, 0xFFFF7F00, 0xFFFFFF00, 0xFF00FF00, 0xFF0000FF, 0xFF4B0082, 0xFF9400D3 };
drawNum(&display, 0x1234ABCD);
//test code
drawNum(&display, cols[0]==0xFFFF0000);
drawNum(&display, cols[1]==0xFFFF7F00);
for (int i=0; i<7; i++)
drawNum(&display, cols[i]);
//test code
drawNum(&display, cols[0]==0xFFFF0000);
drawNum(&display, cols[1]==0xFFFF7F00);
I added the volatile keyword to avoid optimizations by the compiler. It shouldn't mask away the observed wrong output.
I want to initialize an 16-cel-long array with 0, 1, 2 and 3 by blocks of four cels. So here is my first attempt at this:
int main(void) {
int t[16];
int i;
for (i = 0; i<=15; t[i++]=i/4)
{
printf("%d \n", t[i]);
}
return 0;
}
However, here is what I get. I know I can do it differently by just getting the affectation into the for loop, but why does this not work?
EDIT: Please do note that the printf only serves to check what the loop did put in the array.
The initialization works fine; you're just printing the cell before initializing it. Remember that the loop increment is done after each iteration. If you unroll the loop, you have:
i = 0; /* i is now 0 */
print(t[i]); /* prints t[0] */
t[i++] = i/4; /* sets t[0] */
/* i is now 1 */
print(t[i]); /* prints t[1] */
t[i++] = i/4; /* sets t[1] */
/* i is now 2 */
print(t[i]); /* prints t[1] */
/* etc. */
As well as the off-by-one errors with the loop begin/end that have been mentioned in other posts, this code:
t[i++]=i/4
causes undefined behaviour because i is read and written without a sequence point. "Undefined behaviour" means anything can happen: the value could be 3, or 4, or anything else, or the program could crash, etc.
See this thread for more in-depth discussion, and welcome to C..:)
I do not understand what you are trying to accomplish, but please let me show you a similar piece of code, first.
int main(void) {
int t[16];
int i;
//edited the code; providing standard way to do the task
for (i = 0; i<=15; i++)
{
t[i]=i/4;
printf("%d \n", t[i]);
}
return 0;
}
EDIT:
The while loop should be written that way:
int i = 0;
while (i<=15){
t[i] = i%4;
i++;
}
Which means set t[i] equal to i%4 and then increment i.
Since you are a beginner, I've updated the for loop and it now provides a standard way to do your task. It's better to have a simple increment on the third for loop command; do the rest of the job inside the for loop, as described above.
#naltipar: Yeah, I just forgot to initialize the first cel, just like grawity pointed out. Actually, the version I wrote for myself was with i++ but even then, since the third expression is executed after each loop, it sent out the same result. But whatever, it is fixed now.
However, I've got another problem which I'm sure I'm missing on but still can't figure it out:
int i = 0;
while (i<=15)
t[++i] = i%4;
This was first:
for(i = 0; i<=15; t[++i] = i%4);
but it resulted with an infinite loop. So in order to make sure that's not a problem specific to for, I switched to while andthe same thing still happens. That being said, it doesn't occur if i replace ++i by i++. I unrolled the whole loop and everything seems just fine...
I'm a beginner, by the way, in case you were wondering.
A clearer way to write this would be much less error-prone:
for (i = 0; i < 16; ++i)
printf ("%d\n", (t[i] = i % 4));
Personally I'd code something that way, but I'd never recommend it. Moreover, I don't really see much benefit in condensing statements like that, especially in the most important category: execution time. It is perhaps more difficult to optimize, so performance could actually degrade when compared to simply using:
for (i = 0; i < 16; ++i)
{
t[i] = i % 4;
printf ("%d\n", t[i]);
}
Even if it is you reading your own code, you make it difficult for your future self to understand. KISS (Keep It Simple, Stupid), and you'll find code is easier to write now and just as easy to modify later if you need to.
I wrote a simple example with openssl in C. I wanted to compute MD4 hash from my message but I want to save result into a char array. Heres my code with comments which will help you understand what I want to achieve:
#include <string.h>
#include <openssl/md4.h>
#include <stdio.h>
int main()
{
unsigned char digest[MD4_DIGEST_LENGTH];
char string[] = "hello world";
// run md4 for my msg
MD4((unsigned char*)&string, strlen(string), (unsigned char*)&digest);
// save md4 result into char array - doesnt work
char test[MD4_DIGEST_LENGTH];
sprintf(test, "%02x", (unsigned int)digest);
for(int i = 0; i < MD4_DIGEST_LENGTH; i++)
printf("%02x", test[i]);
printf("\n\n");
// print out md4 result - works, but its not intochar array as I wanted it to be
for(int i = 0; i < MD4_DIGEST_LENGTH; i++)
printf("%02x", digest[i]);
printf("\n\n");
// works but i dont understand why 'mdString' is 33 size
char mdString[33];
for(int i = 0; i < MD4_DIGEST_LENGTH; i++)
// and I also dont get i*2 in this loop
sprintf(&mdString[i*2], "%02x", (unsigned int)digest[i]);
printf("md4 digest: %s\n", mdString);
return 0;
}
The question is, why this code below doesnt work, it shows different md4 value than it should be:
char test[MD4_DIGEST_LENGTH];
sprintf(test, "%02x", (unsigned int)digest);
for(int i = 0; i < MD4_DIGEST_LENGTH; i++)
printf("%02x", test[i]);
printf("\n\n");
and how can I know what size should be mdString and why is there i*2 in the last loop? Can anybody explain this?
Firstly, your call to MD4() provides an incorrect address for the string and digest arrays: by using &, you are getting the array's address (char **), not the address of the first character.
Since you are explicitly casting &string and &digest to unsigned char*, the compiler won't warn you. Remove the casts, and you will receive this warning:
warning: passing argument 1 of 'MD4' from incompatible pointer type
So instead call MD4() this way:
MD4(string, strlen(string), digest);
I personally prefer to avoid explicitly casting pointers unless it is really necessary, that way you will catch incorrect type casting much more easily.
Next, you attempt to use sprintf() to convert digest to a hexadecimal integer: sprintf(test, "%02x", (unsigned int)digest);.
Two things wrong here: (a) since digest is essentially a character pointer, ie: memory address, you're turning this address into an unsigned integer and then turning that integer into a hex; (b) you need to loop over the elements of digest and convert each one into a character, snprintf won't do this for you!
I see that you may be relatively new to C given the mistakes made, but don't dispair, making mistakes is the way to learn! :)
If you can afford the book, I highly recommend "C Primer Plus" by Stephen Prata. It's a great intro for anyone starting out programming and it's a very complete reference for later use when you are already comfortable with the language.
Otherwise, there is plenty of material online, and googling "C pointer tutorial" will return several useful results.
Hope this helps!
EDIT:
Forgot to comment about the other snippet of code that does work, but uses 33 bytes to store the string-ized MD4 hash:
// works but i dont understand why 'mdString' is 33 size
char mdString[33];
for(int i = 0; i < MD4_DIGEST_LENGTH; i++)
// and I also dont get i*2 in this loop
sprintf(&mdString[i*2], "%02x", (unsigned int)digest[i]);
printf("md4 digest: %s\n", mdString);
The openssl manpage for MD4() states that the hash is 16 bytes long.
Knowing this, and the fact that each unsigned char can hold a value from 0 to 255, then the maximum hexadecimal representation for any individual element in digest is 0xFF, in other words, 2 ASCII characters per unsigned char.
The reason the size for msString (33) appears cryptic is because MD4_DIGEST_LENGTH should have been used to calculate the size of the array: you need 2 characters to represent each one of the elements in digest + 1 null terminator ('\0') to end the string:
char mdString[(MD4_DIGEST_LENGTH * 2) + 1];
sprintf will print 2 characters to the mdString array whenever it's fed 1 byte from digest, so you need to advance 2 index positions in mdString for each position in digest, hence the use of i * 2. The following produces the same result as using i * 2:
for(int i = 0, j = 0; i < MD4_DIGEST_LENGTH; i++, j += 2)
sprintf(&mdString[j], "%02x", (unsigned int)digest[i]);
I am using Code::Blocks 10.05, and the GNU GCC Compiler.
Basically, I ran into a really strange (and for me, inexplicable) issue that arises when trying to initialize an array outside it's declared size. In words, it's this:
*There is a declared array of size [x][y].
*There is another declared array with size [y-1].
The issue comes up when trying to put values into this second, size [y-1] array, outside of the [y-1] size. When this is attempted, the first array [x][y] will no longer maintain all of its values. I simply don't understand why breaking (or attempting to break) one array would affect the contents of the other. Here is some sample code to see it happening (it is in the broken format. To see the issue vanish, simply change array2[4] to array2[5] (thus eliminating what I have pinpointed to be the problem).
#include <stdio.h>
int main(void)
{
//Declare the array/indices
char array[10][5];
int array2[4]; //to see it work (and verify the issue), change 4 to 5
int i, j;
//Set up use of an input text file to fill the array
FILE *ifp;
ifp = fopen("input.txt", "r");
//Fill the array
for (i = 0; i <= 9; i++)
{
for (j = 0; j <= 5; j++)
{
fscanf(ifp, "%c", &array[i][j]);
//printf("[%d][%d] = %c\n", i, j, array[i][j]);
}
}
for (j = 4; j >= 0; j--)
{
for (i = 0; i <= 9; i++)
{
printf("[%d][%d] = %c\n", i, j, array[i][j]);
}
//PROBLEM LINE*************
array2[j] = 5;
}
fclose(ifp);
return 0;
}
So does anyone know how or why this happens?
Because when you write outside of an array bounds, C lets you. You're just writing to somewhere else in the program.
C is known as the lowest level high level language. To understand what "low level" means, remember that each of these variables you have created you can think of as living in physical memory. An array of integers of length 16 might occupy 64 bytes if integers are size 4. Perhaps they occupy bytes 100-163 (unlikely but I'm not going to make up realistic numbers, also these are usually better thought of in hexadecimal). What occupies byte 164? Maybe another variable in your program. What happens if you write to one past your array of 16 integers? well, it might write to that byte.
C lets you do this. Why? If you can't think of any answers, then maybe you should switch languages. I'm not being pedantic - if this doesn't benefit you then you might want to program in a language in which it is a little harder for you to make weird mistakes like this. But reasons include:
It's faster and smaller. Adding bounds checking takes time and space, so if you're writing code for a microprocessor, or writing a JIT compiler, speed and size really do matter a lot.
If you want to understand machine architecture and go into hardware, e.g. if you're a student, it's a good gateway from programming into OS/hardware/electrical engineering. And much of computer science.
Being close to machine code, it's standard in a way that many other languages and systems have to, or can easily, support some degree of compatibility with.
Other reasons that I would be able to give if I ever actually had to work this close to the machine code.
The moral is: In C, be very careful. You must check your own array bounds. You must clean up your own memory. If you don't, your program often won't crash but will start just doing really weird things without telling you where or why.
for (j = 0; j <= 5; j++)
should be
for (j = 0; j <= 4; j++)
and array2 max index is 3 so
array2[j] = 5;
is also going to be a problem when j == 4.
C array indexes start from 0. So an [X] array valid indexes are from 0 to X-1, thus you get X elements in total.
You should use the < operator, instead of <=, in order to show the same number in both the array declaration [X] and in the expression < X. For instance
int array[10];
...
for (i=0 ; i < 10 ; ++i) ... // instead of `<= 9`
This is less error prone.
If you're outside the bounds of one array, there's always a possibility you'll be inside the bounds of the other.
array2[j] = 5; - This is your problem of overflow.
for (j = 0; j <= 5; j++) - This is also a problem of overflow. Here also you are trying to access 5th index, where you can access only 0th to 4th index.
In the process memory, while calling each function one activation records will be created to keep all the local variables of the function and also it will have some more memory to store the called function address location also. In your function four local variables are there, array, array2, i and j. All these four will be aligned in an order. So if overflow happens it will first tries to overwrite in the variable declared above or below which depends on architecture. If overflow happens for more bytes then it may corrupt the entire stack itself by overwriting some of the local variables of the called functions. This may leads to crash also, Sometimes it may not but it will behave indifferently as you are facing now.