-3

As direct conversion to void ** of other types is not valid is this conversion valid in C?

void swapValues(void **av, void **bv, size_t size)  
{  
    int *a = *av;
    int *b = *bv;
    char array[size];  
    memcpy(array, a, size);  
    memcpy(a, b, size);  
    memcpy(b, array, size);  
}  

int main()  
{  
    int i = 3;  
    int j = 5;  
    int *x = &i;
    int *y = &j;
    void *p = &i;  
    void *q = &j;  

    //this is invalid
    swapValues(&x, &y, sizeof(i));  

    //is this valid
    swapValues(&p, &q, sizeof(i));  
}  
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0___________
  • 60,014
  • 4
  • 34
  • 74
  • https://stackoverflow.com/q/8166502/11683? – GSerg Mar 28 '23 at 09:49
  • What conversion are you referring to? It seems that `void**` types are only initialized on function call and dereferenced within function. – user694733 Mar 28 '23 at 09:50
  • @user694733 Series of conversions – 0___________ Mar 28 '23 at 09:53
  • @user694733 Because it shows proper ways of doing what is being done here, irrespective to the [exact method](https://meta.stackexchange.com/q/66377/147640) shown here? There doesn't seem to be a need to use `void**` to begin with. – GSerg Mar 28 '23 at 09:54
  • 1
    What problem do you see? What compiler/version do you use? – fukanchik Mar 28 '23 at 09:56
  • 2
    It's legal. Which conversion do you suspect isn't legal? – Paul Hankin Mar 28 '23 at 09:56
  • 1
    @GSerg The question is not "How to swap values** only about the language itself. The function is only an example. – 0___________ Mar 28 '23 at 09:56
  • 1
    @fukanchik this is a question about the standard, so compiler/version isn't relevant unless by "version" you mean "edition of the standard". – Paul Hankin Mar 28 '23 at 09:56
  • @PaulHankin any support in C standard? I am no looking for the opinion – 0___________ Mar 28 '23 at 09:57
  • I mean, one version converts `int**` to `void**`, while the other doesn't. So the later version has less wrong with it. – StoryTeller - Unslander Monica Mar 28 '23 at 09:58
  • https://stackoverflow.com/q/75717720/11683? – GSerg Mar 28 '23 at 10:00
  • 2
    You convert `int*` to `void*`, then take the address of the `void*` value. Later you dereference the `void**` to get a `void*`, then convert it back to `int*`. All these steps are individually obviously valid, so any problem would have to be some sort of special rule (like strict aliasing) that makes the code illegal. Without making the question specific about something in the standard (eg: "does this code violate strict aliasing") it's hard to give a proof that it's valid because it's hard to show that something doesn't exist. Maybe others can find a way... – Paul Hankin Mar 28 '23 at 10:04
  • 1
    @GSerg that's not the same -- the question you like to is asking whether it's valid to convert a `void**` into a `void*` and back, whereas this code takes the address of a `void*` to get a `void**`. – Paul Hankin Mar 28 '23 at 10:06
  • Oops - Sorry, I'm getting muddled up, here. – Adrian Mole Mar 28 '23 at 10:18
  • why don't you just change the arguments to void*? why do you need the extra layer of pointers? – user253751 Mar 28 '23 at 10:57
  • @user253751 you do not understand the question. – 0___________ Mar 28 '23 at 10:57
  • 1
    @0___________ I don't understand which conversion you are asking about. It's valid to write `&p` to get the address of `p` - just like any other variable. Why would that not be valid? – user253751 Mar 28 '23 at 10:59
  • (General moan at the world.) I wish there were a standard library function for swapping blocks of memory. It's easy to write one that can swap memory blocks a byte at a time, but it would be hoped that a standard library function would make use of what would otherwise be undefined behavior (if it weren't part of the standard library) to optimize the operation and still use O(1) additional storage. – Ian Abbott Mar 28 '23 at 13:55
  • Interesting DV-es. Any explanation – 0___________ Mar 28 '23 at 16:08

1 Answers1

1

These conversions of argument expressions

swapValues(&p, &q, sizeof(i)); 

to corresponding function parameters

void swapValues(void **av, void **bv, size_t size)

are correct. The first two argument expressions have the type void ** and the corresponding function parameters have the same type void **.

Within the function in these declarations

int *a = *av;
int *b = *bv;

the expressions *av and *bv having the type void * may be used as initializers for the pointers a and b of the type int * without explicit casting because (the C Standard)

1 A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

Actually these declarations

int *a = *av;
int *b = *bv;

are redundant.

You could just write without them

char array[size];  
memcpy(array, *av, size);  
memcpy(*av, *bv, size);  
memcpy(*bv, array, size);
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335