Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

assignment discards 'volatile' qualifier from pointer target type

I have been working with a microprocessor to read the temperature from a sensor and have run into the following warning regarding a volatile declaration.

"assignment discards 'volatile' qualifier from pointer target type"

I was receiving a single value for the temperature and the value wouldn't change until I restarted the program.

  volatile uint16_t temp_value = 0;

  if (value_type == UA_TYPE_UInt16)
  {
      data_value.value_UInt16 = &temp_value; // warning*******

      switch (handle)
      {
            case HANDLE_TEMP1:
              temp_value = ADC_GetConversionValue(ADC3);
              break;
      }
  }

After searching through stack overflow I realized declaring my temp_value as volatile will signify that temp_value will change values. What I could not find on this site was why I can't use a volatile unsigned integer for data_value.value_UInt16

I am storing the ADC value in a server and would like to access the updated value at any time. Is there an additional typecast I should have that points to temp_value? Thanks for reading.

like image 314
rayray Avatar asked Jul 01 '14 16:07

rayray


3 Answers

Your volatile uint16_t temp_value says to the compiler "my variable temp_value may be changed by things that you are not aware of" (particularly, other processes accessing and writing to the memory used to store the variable). Among other things, it prevents the compiler from doing certain optimizations.

When you do :

data_value.value_UInt16 = &temp_value;

(I assume that value_UInt16 is non volatile)

You assign the address of your volatile to a non volatile field : the compiler warns you that it is allowed to make optimizations on it, ignoring that the pointee object might be changed "by things it is not aware of".


Solutions :

  1. Typecast data_value.value_UInt16 = *(uint16_t*)&temp_value, saying to the compiler : "I know what I'm doing, I know that I am ignoring the volatile qualifier here".

Or,

  1. Make value_UInt16 a volatile field as well

Important note:

You tagged C++ and C but :

  • In C++, this is an error (invalid conversion), example here.
  • In C, it is a warning (the one you showed)
like image 59
quantdev Avatar answered Oct 02 '22 02:10

quantdev


You should add the embedded tag.

Unless you can have the linker assign the variable to a specific address, the hardware should always be accessed via pointer or reference:

// Using linker notation:
volatile uint16_t temperature @ "temperature_segment";

// Using pointer, pointer to a volatile uint16_t
uint16_t volatile * temperature = 0x44000025; // Example address

// Because the variable is a pointer to a volatile value,
//    a "snapshot" copy should be made before using.
uint16_t snapshot_temperature = *temperature;
if (snapshot_temperature > 100 /* celsius */)
{
    SYSTEM_FAILURE(TEMPERATURE_OVERHEATING);
}

The volatile keyword instructs the compiler to refrain from optimizing code related to the temperature variable. Also since the target value (hardware register) may change, a snapshot copy should be made before making any comparisons.

like image 20
Thomas Matthews Avatar answered Oct 02 '22 02:10

Thomas Matthews


Volatile works in mostly the same the way that const does. This code

const int i = 1;
int* iPtr = &i; //error

is invalid because it tries to assign a pointer to const to a pointer to non-const. Similarly,

volatile int i = 1;
int* iPtr = &i; //error

is invalid for the same reason, except with volatile. Though your example is incomplete, this is what the issue appears to be.

like image 39
Falias Avatar answered Oct 02 '22 03:10

Falias