【问题标题】:How to const-qualify dynamically allocated data?如何对动态分配的数据进行 const 限定?
【发布时间】:2018-07-25 07:53:39
【问题描述】:

根据this answer,不应该删除常量,因为它们可能一开始就没有被分配。但是,在某些情况下,我想保护动态分配的数据。例如,在管理用户会话时,我想确保像当前用户名这样的数据不会被其他函数意外覆盖,但会话数据在解析时确实是分配的请求。

这是一个代码示例,可以让您更好地了解。不过请记住,事情已经大大简化了。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


const char *request = "www.example.com/index?first-name=SOME&last-name=DUDE";

char *get_username_from_request(const char *req) {
    char *first_name = strstr(req, "first-name") + strlen("first-name") + 1;
    char *last_name = strstr(req, "last-name") + strlen("last-name") + 1;

    char *username = malloc(10);
    memcpy(username, first_name, 4);
    username[4] = ' ';
    memcpy(username + 5, last_name, 4);

    /* The returned string is "SOME DUDE" */
    return username;
}

int main(void) {
    char *username = get_username_from_request(request);
    printf("Welcome, %s.\n", username);
    free(username);
    return 0;
}

我真的想改用const char *username = get_username_from_request(request);,但是当我进行此更改时,Clang 会发出警告:

/Applications/CLion.app/Contents/bin/cmake/bin/cmake --build /Users/nalzok/CLionProjects/zero/cmake-build-debug --target zero -- -j 2
Scanning dependencies of target zero
[ 50%] Building C object CMakeFiles/zero.dir/main.c.o
/Users/nalzok/CLionProjects/zero/main.c:24:10: warning: passing 'const char *' to parameter of type 'void *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
    free(username);
         ^~~~~~~~
/usr/include/stdlib.h:151:18: note: passing argument to parameter here
void     free(void *);
                    ^
1 warning generated.
[100%] Linking C executable zero
[100%] Built target zero

任何想法都值得赞赏。

†​​:嗯,believe it or not,我正在用 C 编写一个 Web 应用程序。

【问题讨论】:

  • @SanderDeDycker 是的,通过强制转换来抑制警告是显而易见的答案,并且有效。但是,这样做时您必须非常小心,所以我想看看是否有人可以提供更安全的替代方案。例如,也许有一种方法可以“锁定”一些内存,防止后续的写入操作。
  • 重复问题中被接受(并且投票最多)的答案并不是唯一的答案 - 它只是社区最支持的答案。其他答案建议不要在这种情况下使用const,例如。你可以做char* u = malloc(...); const char* cu = u; puts(cu); free(u); - 即。 u 仅用于取消分配,cu 用于其他所有操作。
  • The returned string is "SOME DUDE" 并不完全正确。 username 不一定指向 string,因为 username 指向的数据肯定不包含 null 字符
  • @chux 我的错,忘了添加 NUL 终止符。很好的收获。

标签: c pointers memory-management constants qualifiers


【解决方案1】:

首先,您必须了解,无论是否声明const,都不会阻止您编译的代码覆盖任何数据。 Still const 正确性可以帮助您发现代码中的逻辑错误,所以这是个好主意。

对于您的具体问题,我建议您在此处隐藏一些类似 OOP 的信息。你可以例如像这样为用户会话建模:

session.h

#ifndef SESSION_H
#define SESSION_H

typedef struct Session Session;

Session *Session_create(void);
int Session_setUsername(Session *self, const char *username);
const char *Session_Username(const Session *self);
void Session_destroy(Session *self);

#endif

session.c

#include <stdlib.h>
#include <string.h>
#include "session.h"

struct Session
{
    char *username;
};

Session *Session_create(void)
{
    Session *self = calloc(1, sizeof *self);
    return self;
}

int Session_setUsername(Session *self, const char *username)
{
    free(self->username);
    self->username = malloc(strlen(username) + 1);
    if (!self->username) return -1;
    strcpy(self->username, username);
    return 0;
}

const char *Session_Username(const Session *self)
{
    return self->username;
}

void Session_destroy(Session *self)
{
    if (!self) return;
    free(self->username);
    free(self);
}

现在,如果您的代码中某处有const Session *,您将无法操作任何会话数据。您只能获得指向您的用户名的 const 指针。

【讨论】:

    猜你喜欢
    • 2020-03-19
    • 1970-01-01
    • 1970-01-01
    • 2013-06-07
    • 2011-12-21
    • 1970-01-01
    • 1970-01-01
    • 2023-01-11
    • 2016-06-27
    相关资源
    最近更新 更多