Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在c中返回指向不可修改数据的指针_C_Pointers_Constants - Fatal编程技术网

如何在c中返回指向不可修改数据的指针

如何在c中返回指向不可修改数据的指针,c,pointers,constants,C,Pointers,Constants,我希望返回一个指向函数中数据的指针。调用方不应修改该数据。如果调用方将返回值分配给非常量指针,我希望编译器标记一个错误 我知道可以丢弃const,但我希望调用方被迫执行该强制转换,而不仅仅是隐式强制转换或警告。(或者没有警告!就像我正在使用的编译器一样)。我相信我的问题的答案是这是不可能的。我认为没有办法阻止这样的调用方代码编译,如果用户遵从数据(在我的示例中是buf),那么这将是未定义的行为 请注意,我想问的是,在c语言本身中是否有可能做到这一点,如果没有,请解释为什么该标准会阻止这一点。我不

我希望返回一个指向函数中数据的指针。调用方不应修改该数据。如果调用方将返回值分配给非常量指针,我希望编译器标记一个错误

我知道可以丢弃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 &notfound;
}

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