静态c函数可以返回一个本地字符数组吗?

时间:2017-05-03 06:09:03

标签: c string return string-literals storage-duration

在zflog库中,我看到了这段代码

static char* lvl_char(const int lvl)
{
    switch (lvl)
    {
    case ZF_LOG_VERBOSE:
        return "VERBOSE\0";
    case ZF_LOG_DEBUG:
        return "DEBUG\0";
    case ZF_LOG_INFO:
        return "INFO\0";
    case ZF_LOG_WARN:
        return "WARN\0";
    case ZF_LOG_ERROR:
        return "ERROR\0";
    case ZF_LOG_FATAL:
        return "FATAL\0";
    default:
        ASSERT_UNREACHABLE("Bad log level");
        return "?\0";
    }
}

这对我来说似乎很奇怪。我们真的可以从静态函数返回一个本地c字符串吗?

4 个答案:

答案 0 :(得分:6)

功能(此处为静态)的链接根本不重要。也不是"字符串"回;而是返回的是指向char的指针。将指针返回到字符串文字的第一个字符是完全合法的 - 字符串文字保证在程序的整个持续时间内存在。 C11 6.4.5p6声明此处使用的字符串文字用于初始化*" 静态存储持续时间和长度的[匿名]数组足以包含序列&#34 ;.静态存储持续时间意味着其"生命周期是程序的整个执行,其存储值仅在程序启动之前初始化一次。" C11 6.2.4p3

看起来奇怪的是字符串文字末尾的\0,因为文字字符串总是以0结尾,所以基本上"VERBOSE\0"只是用2个零字节而不是通常的1个字节终止;该字符串的strlen将返回7,就像返回"VERBOSE"一样,依此类推。

答案 1 :(得分:5)

你错了,返回的指针没有指向本地char array,而是指向string literal,即static进程。

来自c-standard

  

6.4.5字符串文字

     

<强>语义学对

     

在转换阶段7中,将值为零的字节或代码附加到每个多字节   由字符串文字或文字产生的字符序列.78)多字节字符   然后,序列用于初始化静态存储持续时间和长度的数组   足以包含序列。[...]

Emèphasismine

答案 2 :(得分:3)

  

静态c函数可以返回一个本地字符数组吗?

TL; DR 无论static还是extern,函数都不应返回本地数组,因为它无法有效使用。

现在,详细说明问题,

  

....静态函数?

你在那里,static与“功能”的链接相关联,而不是返回值或类型

此处,static存储说明符表示该函数具有内部链接,即只能从翻译单元访问。

相关C11,章节§6.2.2

  

如果对象或函数的文件范围标识符的声明包含存储类   说明符static,标识符具有内部链接。

OTOH,return语句如

return "FATAL\0"; 
return "DEBUG\0"; ///and so on

实际上将指针返回到string literal的第一个元素,根据定义,它具有静态存储持续时间注1 ,因此返回值为

  • 与返回类型匹配,char * 注2
  • 在return语句后有效。 注3

注1:

引用C11,章节§6.4.5/ P6

  

在转换阶段7中,将值为零的字节或代码附加到每个多字节   由字符串文字或文字产生的字符序列。 78)多字节字符   然后序列用于初始化静态存储持续时间数组和长度   足以包含序列。对于字符串文字,数组元素具有   键入char ,并使用多字节字符的各个字节进行初始化   序列

注2:

引用章节§6.3.2.1/ P3,

  

除非它是sizeof运算符,_Alignof运算符或者&运算符的操作数。   一元static运算符,或者是用于初始化数组的字符串文字,一个表达式   type ''类型''的数组被转换为类型''指向类型''指针的表达式   到数组对象的初始元素并且不是左值。

注3:

引用章节§6.2.4/ P3

  

在没有存储类说明符的情况下声明其标识符的对象   _Thread_local,与外部或内部链接或与存储类   说明符id | key | quantity | product name 1 | menu1 | 2 | Burgers 2 | menu1 | 2 | Drinks 3 | menu1 | 1 | adds on 4 | menu2 | 3 | Burgers 5 | menu2 | 3 | Drinks 6 | menu2 | 2 | adds on 具有静态存储持续时间。它的一生就是整个执行   程序,其存储值仅在程序启动前初始化一次。

答案 3 :(得分:2)

  • 静态c函数可以返回一个本地字符数组吗?不,这会导致未定义的行为。
  • 您的代码是否返回本地char数组?不会。它返回一个指向字符串文字的指针,该字符串文字驻留在只读内存中。这个记忆不是本地的。
  • 你能从任何函数返回指向字符串文字的指针吗?是。
  • 这里的内部链接static常规函数之间是否存在差异?否。