C -- 通过带别名的非 const 指针修改 const
C -- Modify const through aliased non-const pointer
标准 C 中是否允许函数使用别名 int *
修改作为 const int *
给出的 int
?换句话说,下面的代码是否保证在标准C中总是return 42和1?
#include <stdio.h>
void foo(const int *a, int *b)
{
printf("%d\n", *a);
*b = 1;
printf("%d\n", *a);
}
int main(void)
{
int a = 42;
foo(&a, &a);
return 0;
}
是的,你可以做到这一点(如果你知道你可以逃脱惩罚)。
您可能无法摆脱它的一个原因是,如果您要写入的目标内存位于只读保护区(例如常量数据)中,那么您将遇到访问冲突。例如,任何在编译时以可执行文件的只读数据部分结束的常量。大多数平台支持在运行时保护它不被写入。
基本不做
您的示例还有其他问题,可能无法使其成为最佳演示。例如需要在第二个 printf 中重新加载 *a 编译器可能会优化它! (它知道 'a' 没有改变,它知道 'a' 指向一个常量,因此,它不需要通过为第二个 '*a' 表达式执行内存加载来重新加载内存,它可以重用它可能在第一次加载时在寄存器中的值 '*a')。现在,如果您在两者之间添加一个内存屏障,那么您的示例有机会更好地工作。
https://en.wikipedia.org/wiki/Memory_barrier
海湾合作委员会? asm 易失性 ("" : : : "memory"); // 可能在第二次 printf
之前工作
但是您提出的实际问题的主体,是的,如果您知道自己在做什么,那么您就可以做到这一点。
是的,是的。您的程序已定义。
您使用指向 const int 的指针指向非 const int 变量这一事实不会使该变量成为 const,并且仍然可以通过指向 int 的指针或使用原始变量标签进行修改.
在您的示例代码中,您有一个整数。您使用指向它的 const 指针和指向它的非常量指针。当然,通过非常量指针修改整数是合法且定义明确的。
由于两个指针都是指向整数的指针,并且 const 指针不需要指向 const 对象,那么编译器应该期望从 const 指针读取的值可以具有已更改,需要重新加载值。
请注意,如果您使用了 restrict
关键字,情况就不会如此,因为它指定指针参数不会为任何其他指针参数设置别名,因此编译器可以优化重新加载。
是的,保证总是打印 42 和 1。
const int *a
表示指向的值是指针a
.
的常量
尝试在函数中从 a
(*a = 10;
) 取消引用,您将收到错误消息。
但是指针a
不是常量。例如,你可以做 a = b
。
b
可以指向与 a
and/or 修改值相同的地址,就像您在示例中所做的那样。
如果您将 b
指针的值声明为常量 (const int *b
),您会收到一个错误。
我试着这样背:
const int *a
- a 指向一个 int 类型的对象,它不允许修改(任何其他指向该对象的指针都可以做它想做的,取决于它的 declaration/definition)。
标准 C 中是否允许函数使用别名 int *
修改作为 const int *
给出的 int
?换句话说,下面的代码是否保证在标准C中总是return 42和1?
#include <stdio.h>
void foo(const int *a, int *b)
{
printf("%d\n", *a);
*b = 1;
printf("%d\n", *a);
}
int main(void)
{
int a = 42;
foo(&a, &a);
return 0;
}
是的,你可以做到这一点(如果你知道你可以逃脱惩罚)。
您可能无法摆脱它的一个原因是,如果您要写入的目标内存位于只读保护区(例如常量数据)中,那么您将遇到访问冲突。例如,任何在编译时以可执行文件的只读数据部分结束的常量。大多数平台支持在运行时保护它不被写入。
基本不做
您的示例还有其他问题,可能无法使其成为最佳演示。例如需要在第二个 printf 中重新加载 *a 编译器可能会优化它! (它知道 'a' 没有改变,它知道 'a' 指向一个常量,因此,它不需要通过为第二个 '*a' 表达式执行内存加载来重新加载内存,它可以重用它可能在第一次加载时在寄存器中的值 '*a')。现在,如果您在两者之间添加一个内存屏障,那么您的示例有机会更好地工作。
https://en.wikipedia.org/wiki/Memory_barrier 海湾合作委员会? asm 易失性 ("" : : : "memory"); // 可能在第二次 printf
之前工作但是您提出的实际问题的主体,是的,如果您知道自己在做什么,那么您就可以做到这一点。
是的,是的。您的程序已定义。
您使用指向 const int 的指针指向非 const int 变量这一事实不会使该变量成为 const,并且仍然可以通过指向 int 的指针或使用原始变量标签进行修改.
在您的示例代码中,您有一个整数。您使用指向它的 const 指针和指向它的非常量指针。当然,通过非常量指针修改整数是合法且定义明确的。
由于两个指针都是指向整数的指针,并且 const 指针不需要指向 const 对象,那么编译器应该期望从 const 指针读取的值可以具有已更改,需要重新加载值。
请注意,如果您使用了 restrict
关键字,情况就不会如此,因为它指定指针参数不会为任何其他指针参数设置别名,因此编译器可以优化重新加载。
是的,保证总是打印 42 和 1。
const int *a
表示指向的值是指针a
.
尝试在函数中从 a
(*a = 10;
) 取消引用,您将收到错误消息。
但是指针a
不是常量。例如,你可以做 a = b
。
b
可以指向与 a
and/or 修改值相同的地址,就像您在示例中所做的那样。
如果您将 b
指针的值声明为常量 (const int *b
),您会收到一个错误。
我试着这样背:
const int *a
- a 指向一个 int 类型的对象,它不允许修改(任何其他指向该对象的指针都可以做它想做的,取决于它的 declaration/definition)。