0

Let's say that I have a static global variable a, that is cast to an int in a function call during init(). After init(), is a still volatile when used in the function my_function_2?

static volatile int a;

init(void)
{
  my_function_1((int)a);
}

my_function_2(void)
{
/* After init(), is a still volatile? */
}

Does a need to be re-qualified as volatile in my_function_2()? I'm using c99.

LukesDiner
  • 145
  • 8

4 Answers4

2

The variable a will be volatile for it's entire lifetime. If you cast it to some different type and assign it to a new variable, then this new variable will not be volatile unless you specify it so.

volatile means that the compiler doesn't rely on a previously known value and should not apply appropriate optimizations, so if you cast that away and still reference it , than it is undefined behavior.

Here you don't need to declare b as volatile

volatile int a;

void func(int b)
{
     // This doesn't need to be volatile as it will never be changed from the outside, since it was passed by value.
     printf("%d\n", b);
}

init(void)
{
    // Access a and pass the value to func
    // This is fine, because volatile applies only to access of 'a'.
    func(a);
}

Another example:

void func(volatile int *p)
{
     // 'p' needs to be volatile as it will reference 'a' which is volatile
     printf("%d\n", *p);
}

init(void)
{
    func(&a);
}
Devolus
  • 21,661
  • 13
  • 66
  • 113
  • 1
    *"... so if you cast that away, than it is undefined behavior."* This makes it sound as if code in question would be UB, which it's not. – user694733 Apr 20 '21 at 09:27
  • 1
    I updated the phrase to make it more clearer. – Devolus Apr 20 '21 at 09:28
  • @Devolus Thanks for your answer, but this still does not answer my question fully. Can I requalify a as volatile in my_function_2() to avoid undefined behavior? – LukesDiner Apr 20 '21 at 09:38
  • I still think it is unclear: In order for UB to happen, object must be accessed thought non-volatile *pointer*. There is a step that requires taking address of object. It may to obvious to us, but may not be so for the asker. – user694733 Apr 20 '21 at 09:39
  • The `volatile` attribute is required for access to the variable. I updated two examples. – Devolus Apr 20 '21 at 09:46
1

What volatile means is basically that it can be modified externally. This can never change. If you have declared a variable as volatile, then it is volatile.

klutt
  • 30,332
  • 17
  • 55
  • 95
1

It's undefined behavior to refer to the value through a non-qualified type. If you "cast away" volatile you aren't allowed to access that memory location through a non-volatile qualified type.

C17 6.7.3/6:

If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined

You can however still do a copy of it:

static volatile int a;
int b = a;      // ok, lvalue conversion, drops qualifiers during copy
*(int*)&a = ... // undefined behavior
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Ok, if I still wanted a in my example to be volatile, could I re-qualify a as volatile in my_function_2()? – LukesDiner Apr 20 '21 at 09:28
  • I don't think this answer addresses the question. `a` is not accessed through non-qualified type in question. – user694733 Apr 20 '21 at 09:29
  • @LukesDiner, you would have to qualify it only, if you reference the original variable. In your example you pass by value, and the value itself is not affected. – Devolus Apr 20 '21 at 09:30
  • @Devolus I'm sorry, I don't understand your comment. Does it matter if I pass a as value or not? My question is if I cast a to something other than volatile, can I re-qualify a in my_function_2() to avoid undefined behavior? – LukesDiner Apr 20 '21 at 09:34
  • @LukesDiner What is "re-qualify"? If you copy a variable to another variable, the original remains unaffected. If you don't copy but attempt to modify it through a pointer, then it depends on how you attempt to do that. – Lundin Apr 20 '21 at 09:49
  • @LukesDiner I somehow get the feeling that you think the result of `(int)a` that you pass to your function, might be linked to `a` in some way. That is not the case. The copy and the "real" `a` are different data objects and your cast does not affect `a` in any way. – Gerhardh Apr 20 '21 at 10:27
  • It's a good feeling that this kind of u.b can be catched by enabling compiler warnings. `gcc -Wall -Wextra -Wpedantic` issues a `warning: initialization discards ‘volatile’ qualifier from pointer target type [-Wdiscarded-qualifiers]` or `warning: passing argument 1 of ‘func’ discards ‘volatile’ qualifier from pointer target type [-Wdiscarded-qualifiers]`. – Wör Du Schnaffzig Apr 20 '21 at 11:22
1

A cast can only convert a value; it cannot affect an object (the memory of a variable). And values do not have qualifiers such as volatile.

When an object’s value is used in an expression, qualifiers are removed, per C 2018 6.3.2.1 2:

Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion. If the lvalue has qualified type, the value has the unqualified version of the type of the lvalue;…

So, in (int)a, the a is converted from a volatile int lvalue to an int value before the cast occurs. The cast has no effect; it converts an int to an int. Also note that the value is cast—your title asks about “casting a volatile variable,” but it is impossible to cast a variable, because it is automatically converted to its value before the cast.

So the cast has no effect on a. The object a remains volatile. Its value is passed to my_function_1 as a value without the volatile qualifier.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312