C-强制字符串参数位于只读内存中

C-强制字符串参数位于只读内存中,c,gcc,C,Gcc,我正在优化一些代码,我有这样一个函数: const char * gStrPtr = NULL; void foo (const char *str) { gStrPtr = strdup(str); } 到目前为止,foo()仅使用常量字符串调用。例如: const char fooStr[]="Some really long string..."; foo(fooStr); 注意,因为它总是用常量调用,所以我应该能够: void foo (const char *str)

我正在优化一些代码,我有这样一个函数:

const char * gStrPtr = NULL;

void foo (const char *str) {
     gStrPtr = strdup(str);
}
到目前为止,
foo()
仅使用常量字符串调用。例如:

const char fooStr[]="Some really long string...";
foo(fooStr);
注意,因为它总是用常量调用,所以我应该能够:

void foo (const char *str) {
     gStrPtr=str;
}
但是,它打开了一根尖锐的棍子:如果将来有人打破惯例,并尝试使用随后释放的字符串的动态副本调用
foo()
,可能会导致未定义的行为

我想知道是否有可能创建一个编译时甚至运行时检查来检查
str
是否在只读内存中,以避免昂贵的bug追踪

注意:如果我假设str是一个字符串文字,那么我可以用一个宏来实现它,如下所示:

#define foo(str)  foo_func("" str)
这将导致非字符串文本的编译错误。但它也不接受指向常量字符的指针


编辑

我想我会在下面的讨论之后发布这个@CraigEtsy指出使用
\uuu内置常量\up
,这是解决这个问题的最佳方法(但可能足以满足我的需要)。我用这个做了以下测试,得到了这些结果:

void foo(const char *str) {
        if (__builtin_constant_p(*str))
                printf("%s is constant\n", str);
        else
                printf("%s is not constant\n", str);
}

const char globalArray[] = "globalArray";
const char *globalPtr = "globalPtr";

int main()
{
    const char localArray[]="localArray";
    const char *localPtr="localPtr";
    char localNonConst[]="localNonConst";
    foo("literal");     // constant
    foo(localArray);    // not constant
    foo(localPtr);      // constant
    foo(globalArray);   // constant
    foo(globalPtr);     // not constant
    foo(localNonConst); // not constant
}
literal is constant
localArray is not constant
localPtr is constant
globalArray is constant
globalPtr is not constant
localNonConst is not constant
当用-O3编译时,它给出了结果:

void foo(const char *str) {
        if (__builtin_constant_p(*str))
                printf("%s is constant\n", str);
        else
                printf("%s is not constant\n", str);
}

const char globalArray[] = "globalArray";
const char *globalPtr = "globalPtr";

int main()
{
    const char localArray[]="localArray";
    const char *localPtr="localPtr";
    char localNonConst[]="localNonConst";
    foo("literal");     // constant
    foo(localArray);    // not constant
    foo(localPtr);      // constant
    foo(globalArray);   // constant
    foo(globalPtr);     // not constant
    foo(localNonConst); // not constant
}
literal is constant
localArray is not constant
localPtr is constant
globalArray is constant
globalPtr is not constant
localNonConst is not constant

因此,对于我的特殊情况,我可以将
const char arr[]=“str”
切换到
const char*arr=“str”
,然后,在我的
foo()
中,我可以检查该值是否为常量,如果不是,则分配内存并发出运行时警告(并标记一个标志,以便我知道以后是否释放指针…).

我认为没有任何合理的方法在运行时强制执行这一点,至少如果没有比只调用
strdup
要贵很多数量级的机器


如果函数只应将不可变字符串作为参数(这就是您要寻找的词--immutable,意思是它的生命周期将是进程生命周期的剩余部分,其内容在其生命周期的剩余部分不会更改),这需要成为其接口合同的一部分。

问题不是只读内存,而是静态存储(例如,我可以使用
mmap
动态分配只读内存,然后再释放)。我不认为你可以检查。不,你不能这样做。我想我应该检查指针是否位于
.text
部分…如果你
void myfunc(){const char mystr[]=“abc”;foo(mystr);}
然后使用gStrPtr怎么办?
mystr
是否在只读内存中?什么是只读存储器?如果函数返回false,您可以使用[with
gcc
]、
\uuu内置常数\up
函数和执行
strdup
的宏。如果您给它
“abc”
则返回true,否则返回false。然后,您可以对照
.rodata
部分进行范围检查,如果在范围内,则直接进行设置,如果不在范围内,则执行
strdup
。也许太乱了,但我想我还是把它传过去。谢谢。我也得出了同样的结论,但我想我会问一下,以防有人有我忽略的任何聪明的把戏。不幸的是,我不相信未来的程序员会阅读这些评论。我可能会强制每个人使用文本而不是常量字符数组,然后使用宏技巧……您可以将函数定义为宏,并让宏在将其参数传递给函数之前对其进行字符串化,那么如果不绕过宏,就无法传递非字符串文本。;-)根据平台的不同,检查指针是否在只读数据段中比动态数据段便宜得多allocation@M.M:也许吧,但这是一个很大的if,并且有很多警告,除非你是在一个简单的静态链接的情况下。通过动态链接和加载,您需要在每次调用该函数时探测新的共享库,这比分配要昂贵得多。此外,如果库在运行时加载并且可能通过
dlclose
卸载,那么共享库中的只读内存是否算作不可变(这是OP真正需要的)?我想说不,但这里的重点是,这个定义甚至不清楚。