How do I declare an array created using malloc to be volatile in c++

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-03 05:18:11
int volatile * foo;

read from right to left "foo is a pointer to a volatile int"

so whatever int you access through foo, the int will be volatile.

P.S.

int * volatile foo; // "foo is a volatile pointer to an int"

==

volatile int * foo; // foo is a pointer to an int, volatile

Meaning foo is volatile. The second case is really just a leftover of the general right-to-left rule. The lesson to be learned is get in the habit of using

char const * foo;

instead of the more common

const char * foo;

If you want more complicated things like "pointer to function returning pointer to int" to make any sense.

P.S., and this is a biggy (and the main reason I'm adding an answer):

I note that you included "multithreading" as a tag. Do you realize that volatile does little/nothing of good with respect to multithreading?

volatile int* foo;

is the way to go. The volatile type qualifier works just like the const type qualifier. If you wanted a pointer to a constant array of integer you would write:

const int* foo;

whereas

int* const foo;

is a constant pointer to an integer that can itself be changed. volatile works the same way.

Yes, that will work. There is nothing different about the actual memory that is volatile. It is just a way to tell the compiler how to interact with that memory.

I think the second declares the pointer to be volatile, not what it points to. To get that, I think it should be

int * volatile foo;

This syntax is acceptable to gcc, but I'm having trouble convincing myself that it does anything different.

I found a difference with gcc -O3 (full optimization). For this (silly) test code:

volatile int  v [10];
int * volatile p;

int main (void)
{
        v [3] = p [2];
        p [3] = v [2];
        return 0;
}

With volatile, and omitting (x86) instructions which don't change:

    movl    p, %eax
    movl    8(%eax), %eax
    movl    %eax, v+12
    movl    p, %edx
    movl    v+8, %eax
    movl    %eax, 12(%edx)

Without volatile, it skips reloading p:

    movl    p, %eax
    movl    8(%eax), %edx    ; different since p being preserved
    movl    %edx, v+12
    ; 'p' not reloaded here
    movl    v+8, %edx
    movl    %edx, 12(%eax)   ; p reused

After many more science experiments trying to find a difference, I conclude there is no difference. volatile turns off all optimizations related to the variable which would reuse a subsequently set value. At least with x86 gcc (GCC) 4.1.2 20070925 (Red Hat 4.1.2-33). :-)

Thanks very much to wallyk, I was able to devise some code use his method to generate some assembly to prove to myself the difference between the different pointer methods.

using the code: and compiling with -03

int main (void)
{
        while(p[2]);
        return 0;
}

when p is simply declared as pointer, we get stuck in a loop that is impossible to get out of. Note that if this were a multithreaded program and a different thread wrote p[2] = 0, then the program would break out of the while loop and terminate normally.

int * p;
============
LCFI1:
        movq    _p(%rip), %rax  
        movl    8(%rax), %eax   
        testl   %eax, %eax
        jne     L6              
        xorl    %eax, %eax
        leave
        ret
L6:
        jmp     L6

notice that the only instruction for L6 is to goto L6.

==

when p is volatile pointer

int * volatile p;
==============
L3:
        movq    _p(%rip), %rax
        movl    8(%rax), %eax
        testl   %eax, %eax
        jne     L3
        xorl    %eax, %eax
        leave
        ret 

here, the pointer p gets reloaded each loop iteration and as a consequence the array item also gets reloaded. However, this would not be correct if we wanted an array of volatile integers as this would be possible:

int* volatile p;
..
..
int* j;
j = &p[2];
while(j);

and would result in the loop that would be impossible to terminate in a multithreaded program.

==

finally, this is the correct solution as tony nicely explained.

int volatile * p;
LCFI1:
        movq    _p(%rip), %rdx
        addq    $8, %rdx
        .align 4,0x90
L3:
        movl    (%rdx), %eax
        testl   %eax, %eax
        jne     L3
        leave
        ret 

In this case the the address of p[2] is kept in register value and not loaded from memory, but the value of p[2] is reloaded from memory on every loop cycle.

also note that

int volatile * p;
..
..
int* j;
j = &p[2];
while(j);

will generate a compile error.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!