å¯ä»¥åœ¨å †æ ˆä¸Šåˆ†é…consté™æ€å­—符串å—?

时间:2014-11-17 12:07:01

标签: c++ c memory

const char * foo()
{
    return "abcdef";
}

int main()
{
    printf("%s", foo());
}

符åˆæ ‡å‡†çš„编译器是å¦å¯ä»¥å†³å®šåœ¨å †æ ˆä¸Šåˆ†é…"abcdef"?å³æ ‡å‡†ä¸­çš„内容强制编译器在.data部分中分é…它?

5 个答案:

答案 0 :(得分:25)

从C ++规范§2.14.5/ 8中获å–字符串文字;

  

普通字符串文字和UTF-8字符串文字也称为窄字符串文字。窄字符串文字的类型为“ n const charâ€æ•°ç»„,其中 n 是下é¢å®šä¹‰çš„字符串大å°ï¼Œå¹¶ä¸”具有é™æ€å­˜å‚¨æŒç»­æ—¶é—´ï¼ˆ3.7)。

值得一æ的是,é™æ€å­˜å‚¨æŒç»­æ—¶é—´ï¼Œé€‚用于所有字符串文字;å› æ­¤L"",u"",U""ç­‰; §2.14.5/ 10-12。

å过æ¥ï¼Œå¯¹äºŽé™æ€å­˜å‚¨æŒç»­æ—¶é—´Â§3.7.1/ 1;

  

所有没有动æ€å­˜å‚¨æŒç»­æ—¶é—´ï¼Œæ²¡æœ‰çº¿ç¨‹å­˜å‚¨æŒç»­æ—¶é—´ä¸”ä¸æ˜¯æœ¬åœ°çš„å˜é‡éƒ½å…·æœ‰é™æ€å­˜å‚¨æŒç»­æ—¶é—´ã€‚这些实体的存储应在程åºæœŸé—´æŒç»­ï¼ˆ3.6.2,3.6.3)。

因此,您的字符串"abcdef"将在程åºçš„æŒç»­æ—¶é—´å†…存在。编译器å¯ä»¥é€‰æ‹©å­˜å‚¨å®ƒçš„ä½ç½®ï¼ˆè¿™å¯èƒ½æ˜¯ç³»ç»Ÿçº¦æŸï¼‰ï¼Œä½†å®ƒå¿…é¡»ä¿æŒæœ‰æ•ˆã€‚

对于C语言规范(C11 draft n1570),字符串文字§6.4.5/ 6;

  

在转æ¢é˜¶æ®µ7中,将值为零的字节或代ç é™„加到由字符串文字或文字产生的æ¯ä¸ªå¤šå­—节字符åºåˆ—。然åŽä½¿ç”¨å¤šå­—节字符åºåˆ—åˆå§‹åŒ–é™æ€å­˜å‚¨æŒç»­æ—¶é—´æ•°ç»„,并且长度足以包å«åºåˆ—。对于字符串文字,数组元素的类型为char,并使用多字节字符åºåˆ—çš„å„个字节进行åˆå§‹åŒ–。

é™æ€å­˜å‚¨æŒç»­æ—¶é—´Â§6.2.4/ 3;

  

声明标识符的对象没有存储类说明符_Thread_local,并且具有外部或内部链接或存储类说明符static,具有é™æ€å­˜å‚¨æŒç»­æ—¶é—´ã€‚ 它的生命周期是整个程åºçš„执行,它的存​​储值åªåœ¨ç¨‹åºå¯åŠ¨ä¹‹å‰åˆå§‹åŒ–一次。

该ä½ç½®çš„相åŒç†ç”±é€‚用(很å¯èƒ½æ˜¯ç³»ç»Ÿçº¦æŸï¼‰ï¼Œä½†å¿…须在程åºæœŸé—´ä¿æŒæœ‰æ•ˆã€‚

答案 1 :(得分:6)

  

标准中的内容强制编译器在.data上分é…它   部?

无。但它肯定ä¸ä¼šåœ¨å †æ ˆä¸Šï¼Œå› ä¸ºæŒ‡å‘字符串文字的指针永远ä¸ä¼šå¤±æ•ˆï¼ˆå› ä¸ºæ–‡å­—具有é™æ€å­˜å‚¨æŒç»­æ—¶é—´ 1 ),并且堆栈上的值会被æŸäº›å…¶ä»–帧覆盖点。具有é™æ€å­˜å‚¨æŒç»­æ—¶é—´çš„对象通常ä½äºŽä¸“用于此的部分 - .data部分。

在as-if规则下,如果程åºçš„å¯è§‚察行为没有改å˜ï¼Œä»–å¯ä»¥æŠŠå®ƒæ”¾åœ¨å †æ ˆä¸Š;但这ç§æƒ…况ä¸å¤ªå¯èƒ½å‘生,因为这ä¸ä¼šä»¥ä»»ä½•æ–¹å¼ä½¿ç¨‹åºçš„性能å—益(并且还没有编写无æ„义的相关编译器)。


1) [lex.string] / 8:

  

也引用普通的字符串文字和UTF-8字符串文字   作为窄字符串文字。窄字符串文字的类型为“数组†  of n const char“,其中 n 是下é¢å®šä¹‰çš„字符串的大å°ï¼Œ   并且具有é™æ€å­˜å‚¨æŒç»­æ—¶é—´ï¼ˆ3.7)。

答案 2 :(得分:6)

å‚考N1570(C11è‰æ¡ˆï¼‰6.4.5/6 字符串文字(强调我的未æ¥ï¼‰ï¼š

  

在转æ¢é˜¶æ®µ7中,将值为零的字节或代ç é™„加到æ¯ä¸ªå¤šå­—节   由字符串文字或文字产生的字符åºåˆ—。 78)   然åŽä½¿ç”¨å¤šå­—节字符åºåˆ—åˆå§‹åŒ–数组   é™æ€å­˜å‚¨æŒç»­æ—¶é—´å’Œé•¿åº¦è¶³ä»¥åŒ…å« Â Â åºåˆ—。对于字符串文字,数组元素具有类型   char,并使用多字节的å•ä¸ªå­—节进行åˆå§‹åŒ–   字符åºåˆ—。

è¿™æ„味ç€å­—符串文字具有整个程åºæ‰§è¡Œçš„生命周期,如6.2.4/3 对象的存储æŒç»­æ—¶é—´ä¸­æ‰€è¿°ï¼š

  

在没有存储类的情况下声明其标识符的对象   说明符_Thread_local,并且具有外部或内部链接或存储类说明符static,具有é™æ€å­˜å‚¨æŒç»­æ—¶é—´ã€‚它的   lifetime是程åºçš„整个执行åŠå…¶å­˜å‚¨å€¼   仅在程åºå¯åŠ¨ä¹‹å‰åˆå§‹åŒ–。

编译器ä¸å¤ªå¯èƒ½å°†å®ƒä»¬æ”¾åœ¨å †æ ˆä¸Šï¼Œå› ä¸ºå®ƒçš„性质(æ示:在函数调用之间ä¿ç•™ï¼‰ã€‚

请注æ„,C Standard并未明确ç¦æ­¢åœ¨å­—符串上放置字符串文字。事实上,它甚至没有将这样的术语定义为堆栈,也ä¸å®šä¹‰.data部分。这å–决于编译器,选择符åˆæ ‡å‡†çš„任何数æ®æ”¾ç½®ã€‚

答案 3 :(得分:3)

之å‰çš„答案已ç»ä»Žæ ‡å‡†ä¸­å¼•ç”¨ï¼Œæ‰€ä»¥æˆ‘将采用逻辑方法。

您å¯ä»¥å°†æ­¤æ–‡å­—字符串从ROæ•°æ®éƒ¨åˆ†å¤åˆ¶åˆ°æ¯æ¬¡è°ƒç”¨è¯¥å‡½æ•°çš„堆栈中:

const char* foo()
{
    const char str[] = "abcdef";
    return str;
}

但是这个函数返回一个指针。

你肯定ä¸å¸Œæœ›è¿™ä¸ªæŒ‡é’ˆåŒ…å«å †æ ˆä¸­çš„地å€ã€‚

因此,在堆栈上分é…文字字符串是没有æ„义的。

答案 4 :(得分:3)

é™æ€æŒç»­æ—¶é—´çš„所有内容必须ä¿æŒåˆ†é…,直到程åºé€€å‡º;这些东西å¯èƒ½ä½äºŽå †æ ˆä¸Šï¼Œä½†åªæœ‰åœ¨æ‰§è¡Œä»»ä½•ç”¨æˆ·ä»£ç ä¹‹å‰åˆ†é…它们。这样的设计是ä¸å¯»å¸¸çš„,但在例如å¯èƒ½æ˜¯æœ‰åˆ©çš„。一个æ’件架构,希望有几个线程åŒæ—¶è¿è¡Œä¸€ä¸ªæ’件,让æ¯ä¸ªçº¿ç¨‹çš„实例完全独立è¿è¡Œã€‚如果架构将æ’件的所有实例共享相åŒçš„é™æ€æ•°æ®ï¼Œé‚£ä¹ˆè‡³å°‘从æ’件架构的角度æ¥çœ‹ï¼Œä¸åº”该共享的数æ®ä¸åº”该是é™æ€çš„。虽然让æ¯ä¸ªå®žä¾‹å°†å…¶é™æ€æ•°æ®å­˜å‚¨åœ¨ä»Žå †è¯·æ±‚的空间å—中å¯èƒ½æ›´å¥½ï¼Œä½†è¿™éœ€è¦è®©æ¯ä¸ªå®žä¾‹åœ¨å®Œæˆæ—¶é‡Šæ”¾è¯¥ç©ºé—´å—。让æ¯ä¸ªæ’件实例在其堆栈上分é…其所有数æ®ï¼ˆåŒ…括适当大å°çš„char[],在è¿è¡Œç”¨æˆ·ä»£ç ä¹‹å‰å°†å…¶ç»†åˆ†ä¸ºæ»¡è¶³malloc()或new请求)确ä¿æ€æ­»ä¸Žå®žä¾‹å…³è”的线程会释放与之关è”的存储。