17
volatile uint8_t reset_mask[768] = {0}

Now I am setting the values of this array elements to 1 during one of internal operations.

In another functional call, I need to set all the elements of this array to 0. One way is by using for loop but I believe better way to assign all the elements of array is by using memset

memset(reset_mask, 0, sizeof(reset_mask));

but I am getting this error :- "cast from type 'volatile uint8_t* {aka volatile unsigned char*}' to type 'void*' casts away qualifiers"

In case we cannot use memset here, is there a better way to set all elements of this volatile array in one go?

Ankur
  • 191
  • 1
  • 7
  • 7
    `std::fill(std::begin(reset_mask), std::end(reset_mask), 0);` works. – R. Martinho Fernandes Jun 17 '13 at 09:56
  • @R.MartinhoFernandes That should be an answer (since it is really the only correct answer). In C, of course, he'd have to use his own loop. – James Kanze Jun 17 '13 at 10:02
  • What are you using the volatile array for? You may have to disable some/all interrupts? – Martin James Jun 17 '13 at 10:09
  • 1
    Is there any good reason why you are using volatile. Volatile should only ever be used for memory mapped FIFO registers where memset is totally inappropriate. Please do not use volatile in multithreading. Rather use appropriate locks. – doron Jun 17 '13 at 10:31
  • Volatile is used because reset_mask is used by multiple PUs concurrently running the same code and modifying the value of array elements. In my situation, there is a condition placed where it checks while(reset_mask[pu]==0){..//It is not setting reset_mask inside this loop so if we don't use volatile, due to compiler optimization this may get optimized into while(true). Usage of Volatile keyword prevents such compiler optimization.......} – Ankur Jun 17 '13 at 10:34
  • 2
    Use locks. Remember that read and writes may be reordered. Volatile just effect compilation and has no effect on CPU behaviour. If you want to guarantee read and write ordering across threads, your CPU will provide Data Memory Barriers. There will be incorporated into the appropriate locks, Volatile is not the way to do this. – doron Jun 17 '13 at 10:44
  • Take a look at: http://stackoverflow.com/questions/3612505/is-volatile-needed-in-this-multi-threaded-c-code/3612551#3612551 – doron Jun 17 '13 at 10:45
  • @doron - 'Please do not use volatile in multithreading' - indeed. I assumed 'reset_mask' was some kind of drivery, interruptery thing where 'volatile' was actually useful. – Martin James Jun 17 '13 at 11:28

2 Answers2

9

You "can" use memset casting away volatileness with const_cast, but it will remove the volatile semantics. So unless that is okay for you, you're stuck with the loop version. Unless your implementation gives you a version of memset that takes volatile* and is documented to do your job. (I'd think unlikely outside embedded systems, would surprise me even there.)

Balog Pal
  • 16,195
  • 2
  • 23
  • 37
5

As Balog Pal said, casting away volatile to call memset breaks the volatile semantics. The whole memset may get optimized away, or undefined behaviour badness happens.

Either write your own loop to zero out the array, or use this memset_volatile:

void memset_volatile(volatile void *s, char c, size_t n)
{
    volatile char *p = s;
    while (n-- > 0) {
        *p++ = c;
    }
}

The real memset also returns s and c is an int, but this version is cleaner to me.

It is quite unclear if the compiler is allowed to optimize this function to write more than one byte at a time, so if the array is very large it could be a bit slow.

Edit: Since C11 there is memset_s. It doesn't take a pointer to volatile for some reason, so you have to cast away the volatile. It is however guaranteed to actually overwrite the memory.

Tor Klingberg
  • 4,790
  • 6
  • 41
  • 51