Constant int incement [duplicate] - c

This question already has answers here:
warning: assignment discards qualifiers from pointer target type
(2 answers)
Closed 6 years ago.
Consider below two cases.
case1: compiler error --> error: increment of read-only variable ‘x’
#include<stdio.h>
main()
{
const int x=5;
printf("%d",++x);
}
case2: Ran successfully with output 6. why?
#include<stdio.h>
main()
{
const int x=5;
int *ptr=&x;
++(*ptr);
printf("%d",x);
}

int *ptr=&x; is a constraint violation, i.e. an "error", invalid code. C language does not support implicit conversion of const int * type to int * type. Your compiler surely issued a diagnostic message for this.
After that diagnostic message your program's behavior is no longer defined by C language, assuming your compiler somehow agreed to compile it. Many C compilers can be configured to refuse to compile this code, even if they accept it in default mode.
You could force the conversion by using a cast
int *ptr = (int *) &x;
This would get rid of the above constraint violation. The compilers would now have to accept your code (with some caveats). But after that modification, the attempt to do ++*ptr would trigger undefined behavior, because it is an attempt to modify a const object.

Related

C string standard library, memset and discarded volatile keyword [duplicate]

This question already has answers here:
Is `memcpy((void *)dest, src, n)` with a `volatile` array safe?
(3 answers)
Closed 2 years ago.
I'm getting warning like this on xc32 compiler (gcc based microcontroller compiler, not open-source).
modem_uart.c:66:5: warning: passing argument 1 of 'memset' discards
'volatile' qualifier from pointer target type [enabled by default]
Here is the code:
#include <string.h>
// (...)
volatile char rxbuf[MODEM_UART_RXBUF_SIZE];
// (...)
void some_function(void)
{
// (...)
memset(rxbuf, 0, MODEM_UART_RXBUF_SIZE); // <- warning here
// (...)
}
Can someone explain why compiler is discarding volatile?
The specification in the standard of memset has the following declaration:
void *memset(void *s, int c, size_t n);
The first argument is not declared volatile void *s. So it doesn't guarantee to obey the extra restrictions on accessing volatile data. Making every call to memset() treat the destination as if were volatile would impose an unnecessary performance impact.
If you need those assurances, you should replace the memset() call with an explicit loop.
for (int i = 0; i < MODEM_UART_RXBUF_SIZE; i++) {
rxbuf[i] = 0;
}
If you need this from multiple places in your code, you could put it into a volatile_memset() function.
Your platform doesn't provide a memset function that is guaranteed to respect whatever guarantees it provides for volatile. So, in order to call memset, the compiler must discard the volatile qualifier on rxbuf.
You should probably write your own implementation of memset that respects whatever guarantees you expect volatile to provide for you. This answer includes one for memcpy to solve a similar problem. If there are no such guarantees, then get rid of volatile.

Why isn't my data protected even if I use "const" in C? [duplicate]

This question already has answers here:
In C, can a const variable be modified via a pointer?
(4 answers)
Closed 6 years ago.
#include <stdio.h>
int main()
{
const int marbles[10] = { 1,2,3,4,5,6,7,8,9,10 };
int *ptr = marbles;
*ptr = 100;
printf("%d \n", marbles[0]); // output is "100"
}
I used const to protect the array. So I thought int *ptr = marbles would cause error. Otherwise by using pointer, it would enable user to change the data in the array. But surprisingly the output is "100". Isn't C suppose to protect the array from any kind of methods when I use const?
When I tried to compile the program, it showed this warning. So I guess when you initialize the pointer, const keyword loses its effect.
In function ‘main’:
try.c:6:16: warning: **initialization discards ‘const’ qualifier from pointer** target type [enabled by default]
int *ptr = marbles;
So I thought int *ptr = marbles would cause error.
It is an "error". C language considers this initialization a constraint violation, which is what we typically call an "error".
The compiler is required to issue a diagnostic message in response to a constraint violation, which is exactly what it did in your case.
Typically, it is your responsibility to analyze diagnostic message issued by your compiler and figure out which are "innocent" and which indicate serious errors.

Modification of const int through a non-const pointer [duplicate]

This question already has answers here:
can casting away constness lead to undefined behavior? [duplicate]
(5 answers)
Closed 7 years ago.
#include <stdio.h>
int main(){
const int a = 10;
*(int*)(&a) = 9; // modify a
printf("%d", a);
return 0;
}
When I run this code on Xcode, the output is 10 (not changed)
When I run this code on Visual Studio Community, the output is 9 (changed)
Why?
This program would compile but exhibits undefined behavior and may output 9 or 10 or something else or may crash who knows.
When you say a is const, you promise that you won't try change the value of a directly or indirectly and compiler may make certain assumptions. If you break the promise unexpected things may happen.
Q: why?
Ans: undefined behaviour.
To explain, if you try to modify a const variable value by accessing is through some non-const pointer, it invokes undefined behaviour.
As per C11 standard, chapter 6.7.3, paragraph 6.
If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined.
Note: The recommended signature of main() is int main(void).
const keyword is used not to change the value of variable. If its done forcefully results may be unexpected

Changing value of const int using using pointer [duplicate]

This question already has answers here:
Const variable changed with pointer in C
(5 answers)
Closed 9 years ago.
I wrote a C program in gcc and it's giving me very unexpected output. The code is :
#include<stdio.h>
int main(){
const int x=10;
int *p=&x;
*p=11;
printf("%d\n",*p);
printf("%d",x);
printf("\n%u\n",p);
printf("%u", &x);
}
Here output is:
11
10
37814068
37814068
Why do p and &x give the same address(37814068) but different values(5,10)??
Modifying a const variable (directly or through a pointer) invokes undefined behavior. You may not get the same result in another machine.
In the C Standard mofiying a constant is an undefined behaviour. It means that anything could happen it depends on the machine you're running and the compiler your using. In some cases constants are puted on read-only memory and modifying it's value will cause the program to crash.
Exemple of the error generated by the GCC compiler:
error: assignment of read-only location '* p'
*p = 11;
^

why compiler restricts global variable always to be initialized by constant value? [duplicate]

This question already has answers here:
Error "initializer element is not constant" when trying to initialize variable with const
(8 answers)
Closed 9 years ago.
Let me exemplify this,
int a = 100;
int b = a;
int main(int argc, char **argv, char ** env)
{
printf("The value of b=%d\r\n",b);
return 0;
}
Now, I get the compilation error as expected.
[joshis1#localhost global_var]$ gcc global_var.c -o global_var.out
global_var.c:4:1: error: initializer element is not constant
int b = a;
^
What I want to learn here is why do I get the error? why compiler restricts this operation.
I understand that initialized global variables are stored in Data segments. The compiler could have first resolved the value of a,and then could have assigned the same value to b. Why it lacks this feature? Is it complex for compiler to do? Is there any rationale behind this functionality or just a pitfall of C?
The official documentation, taken from line 1644, 6.7.8 Initialization, says:
All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
Why the rule exists is a more difficult question - perhaps as you suggest it is difficult for the compiler to do. In C++ such an expression is valid, but global initialiser may invoke constructors, etc, whereas for C, to keep things compact, globals are evaluated at the compile phase. int b = a; is evaluable at compile time, but what about int b = a + c;? int b = pow(a, 2);? Where would you stop? C decides that not allowing you to start is the best solution.
From your comment:
...how can I force compiler to make this work?
Well you can't make the compiler accept what you have but you can accomplish your goal by defining the value you want to assign to both variables.
#define INITIAL_VALUE_FOR_A 100
int a = INITIAL_VALUE_FOR_A;
int b = INITIAL_VALUE_FOR_A;
Now if you need to change the initial value, you only need to change it in one place;
C is portable to very simple, small machines. Evaluating expressions that aren't constant requires runtime code, in a function. In embedded programming you might not want any functions (or code) that you did not explicitly program.
Your compiler probably will evaluate the initializer as a language extension, if configured with different options. If that fails, you could try C++ (even just the C-like subset) or another language that does more things you like :v) .
Others have stated why initializers in general can't be allowed to be arbitrary expressions.
The way to "force the compiler to accept the code" is to change the code. The canonical way to perform arbitrary initialization of file scope, external linkage (vulgo: "global") variables is to call an initialization function at the start of main() that does all the initialization in the sequence you need:
#include <stdio.h>
int a;
int b;
void init(void)
{
a = 100;
b = a;
}
int main(int argc, char **argv)
{
init();
printf("The value of b=%d\n", b);
return 0;
}

Resources