如何在c中返回指向不可修改数据的指针
我希望返回一个指向函数中数据的指针。调用方不应修改该数据。如果调用方将返回值分配给非常量指针,我希望编译器标记一个错误 我知道可以丢弃const,但我希望调用方被迫执行该强制转换,而不仅仅是隐式强制转换或警告。(或者没有警告!就像我正在使用的编译器一样)。我相信我的问题的答案是这是不可能的。我认为没有办法阻止这样的调用方代码编译,如果用户遵从数据(在我的示例中是buf),那么这将是未定义的行为 请注意,我想问的是,在c语言本身中是否有可能做到这一点,如果没有,请解释为什么该标准会阻止这一点。我不是在寻找使用特定编译器命令行使此特定示例标记错误的方法如何在c中返回指向不可修改数据的指针,c,pointers,constants,C,Pointers,Constants,我希望返回一个指向函数中数据的指针。调用方不应修改该数据。如果调用方将返回值分配给非常量指针,我希望编译器标记一个错误 我知道可以丢弃const,但我希望调用方被迫执行该强制转换,而不仅仅是隐式强制转换或警告。(或者没有警告!就像我正在使用的编译器一样)。我相信我的问题的答案是这是不可能的。我认为没有办法阻止这样的调用方代码编译,如果用户遵从数据(在我的示例中是buf),那么这将是未定义的行为 请注意,我想问的是,在c语言本身中是否有可能做到这一点,如果没有,请解释为什么该标准会阻止这一点。我不
#include "stdio.h"
const int* get_buf_2()
{
static int arr[10] = {1};
return arr;
}
void get_buf(const int ** buf)
{
static int arr[10] = {1};
*buf = arr;
}
int main(int argc, char const *argv[])
{
int *buf;
get_buf(&buf);
printf("%d %d\n", buf[0], buf[1]);
buf = get_buf_2();
printf("%d %d\n", buf[0], buf[1]);
const int cbuf[10];
buf = cbuf;
return 0;
}
每次指针buf从指针分配到const时,此代码都会生成3个带有clang和gcc的警告。两个不同的警告:
warning: passing 'int **' to parameter of type 'const int **' discards
qualifiers in nested pointer types [-Wincompatible-pointer-types-discards-qualifiers]
warning: assigning to 'int *' from 'const int *' discards qualifiers
[-Wincompatible-pointer-types-discards-qualifiers]
可能相关:
问题是您在
main
中声明了buf
:
int *buf;
只需将其更改为:
const int *buf;
这应该会注意到警告。我不完全清楚您在寻找什么,但没有任何东西阻止您将地址返回到
只读位置。例如,函数number
返回一个const int*
指针,指向data
中的值的地址:
#include <stdio.h>
const int data[] = { 1, 2, 3, 4 };
const int notfound = -1;
const int *number (unsigned n)
{
if (n < sizeof data / sizeof *data)
return &data[n];
return ¬found;
}
int main (int argc, char **argv) {
int v = argc > 1 ? *argv[1] - '0' : 2;
const int *n = number (v);
#ifdef TESTERR
(*n)++; /* <== error: increment of read-only location ‘*n’ */
#endif
printf ("v : %d\n", *n);
return 0;
}
尝试修改返回的示例
但是,如果您试图修改number
返回的位置处的值,编译器将生成一个错误,而不提供任何特定选项
$ gcc -Wall -Wextra -pedantic -std=gnu11 -o bin/fn_const_ptr fn_const_ptr.c -DTESTERR
fn_const_ptr.c: In function ‘main’:
fn_const_ptr.c:20:5: error: increment of read-only location ‘*n’
(*n)++; /* <== error: increment of read-only location ‘*n’ */
^
让我知道这是否是您的意图。回答您的问题,“我想问的是,是否有可能做到这一点[…],如果没有,请解释标准为什么阻止这样做。”
对于第一部分:const
是C为此目的提供的唯一工具
如果您的用例允许,您可以构建一个类似迭代器的结构和支持函数,以提供元素对元素的访问,同时保护实际存储。(但如果适合,也可以将API更改为intget\u len()
/charget\u char(intidx)
接口)
对于第二部分:根据:
6.5.16.1简单作业
1下列其中一项应适用:
[……]
-左操作数具有原子、限定或非限定指针类型,并且(考虑到左值转换后左操作数将具有的类型),两个操作数都是指向兼容类型的限定或非限定版本的指针,左指向的类型具有右指向的类型的所有限定符强>
这种情况涵盖了对指针的赋值(当赋值的两个操作数都不是void*
时),它明确要求左侧指向的类型具有右侧指向的类型的所有限定符。由于const
就是这样一个限定符,您的编译器甚至不警告忽略const
的赋值,这就是没有实现规范
(为清楚起见,规范使用“限定指针”表示*
。它使用“指向的类型上的限定符”表示*
)
[社论评论:我会冒险猜测,甚至没有警告的编译器都是针对嵌入式开发的。嵌入式开发人员似乎经常忍受糟糕的工具。你好,我意识到现在我还不够清楚,我想通过将警告转化为错误来消除这些警告。我希望编译器告诉我,我不允许拥有指向该数据的可修改指针。我将澄清这个问题。这个回答只考虑了标题,而不是标题question@EvanBenn如果你想把战争变成错误,使用这个编译标志-Werror
@evanben哦,我现在明白了。我原本以为你只是想消除这些警告。至于将其转化为错误,这将是特定于编译器的。正如Thiru所建议的,您可以将-Werror
与gcc
一起使用。请注意,您可以使用-Werror=x
使其更具体,其中x
是一类特定的警告(请参阅gcc
文档了解具体细节)。@lockcmpxchg8b是的,我现在看到了。我原本以为OP只是想消除警告。我想您不能更改接口,以便调用者提供一个目标缓冲区,您可以将不可修改的数据复制到其中?简单地使用Werror怎么样?
$ gcc -Wall -Wextra -pedantic -std=gnu11 -o bin/fn_const_ptr fn_const_ptr.c -DTESTERR
fn_const_ptr.c: In function ‘main’:
fn_const_ptr.c:20:5: error: increment of read-only location ‘*n’
(*n)++; /* <== error: increment of read-only location ‘*n’ */
^
int *p;
...
#ifdef TESTERR
p = (int*)n;
(*p)++; /* SegFault */
#endif