Home > Blockchain >  What does *(long *) and *(int*) mean?
What does *(long *) and *(int*) mean?

Time:09-17

Could you explain what the next two lines do?

// Line 1
*(long *)add1= *(long *)add2;
// Line 2
*(int *)add1 = *(int *)add2;

Edit 1. I add the complete block of code of the function I test. PS It is only a part of the skript. [original Skript]

It is a custom memcpy function to copy block of memory from A to B.


    (2)
    while(word_left > 0){
        *(char *)temp   = *(char *)src  ;
        word_left --;
    }

    return (void *)dest;
}

Mr Vlag was so kind and explained what the lines in the part(1) mean.

My question is regarding to the part(2). This part should solve a problem if the memory address overlaps.

Why do we use char here? Why can we not use long or int?

CodePudding user response:

In the both records const6ructions ( long * ) and ( int * ) mean casting pointers correspondingly to pointer types long * and int *. Then these pointers are dereferenced *( long * )addr2 and *( int * )addr2 to get access to pointed objects values of which are assigned to other objects that are obtained also through casting and dereferencing pointers.

To make it more clear consider a demonstrative program.

#include <stdio.h>

int main(void) 
{
    int x = 10;
    int y = 0;
    
    printf( "x = %d, y = %d\n", x, y );

    void *p1 = &x;
    void *p2 = &y;
    
    *( int * )p2 = *( int * )p1;
    
    printf( "x = %d, y = %d\n", x, y );
    
    return 0;
}

The program output is

x = 10, y = 0
x = 10, y = 10

In this program for example the pointer p1 of the type void * due to the casting ( int * )p1 is interpreted as a pointer of the type int * that points to an object of the type int (in this case it points to the object x). Now dereferencing this pointer *( int * )p1 you get a direct access to the pointed object x.

You may not just write for example

y = *p1;

because you may not dereference a void pointer because the type void is an incomplete type. So the compiler will not know how to interpret the pointed memory.

CodePudding user response:

The C standard function memcpy is sometimes implemented in a similar manner like this. This function has no requirement that the addresses passed by the application are aligned.

A naive version could just run a for loop using char byte type and copy everything byte by byte. Then we don't have to worry about alignment, but such code will be slow since it isn't taking advantage of the CPU data width.

More efficient code will do the copying on the largest data size that the CPU can handle in a single instruction, such as for example 32 or 64 bits. This is supposedly what this code is supposed to do. If we do that, we still have to take care of potential misalignment in the start and trailing bytes in the end of the segment to be copied. That part has to be copied byte by byte, similar to the code at the end of your function.

This is the first place where we notice that the code you posted is severely broken - it doesn't handle initial misalignment.

Worse yet, it assumes that int cpu_size = sizeof(char *); gives the CPU data width size which is just plain wrong - the size of a pointer corresponds to the address bus width which is not the same thing as the maximum data register width on a whole lot of existing systems.

Another problem/bug is that temp = cpu_size; isn't valid C code but a non-standard gcc extension. We can't do pointer arithmetic on void pointers.

Cosmetic bugs are the casts between void* and void*. Obviously we don't need to cast between the same types. Every object pointer in C can in fact get implicitly converted to a void* without casts, given that qualifiers (const etc) match.

And finally, we can't run code such as this on a standard C compiler, because de-referencing some unknown data with a value access of long or int is very likely undefined behavior and a strict aliasing violation. What is the strict aliasing rule? The actual memcpy function as part of the standard lib isn't written in standard C and can't get compiled as it. (It is quite likely written in assembler and often inlined in the calling code.)

So what you should do with this code here is to delete it and forget that you ever saw it, because there's nothing to learn from it. The person who wrote it didn't know what they were doing. With the "Yoda conditions" obfuscation it looks like code from the 1980s - if so, then I'd recommend to avoid studying really old code like that.

  • Related