簡體   English   中英

C和C ++之間的字符串文字差異

[英]String Literal Differences Between C and C++

據我所知,在C ++ 11之前,字符串文字在C和C ++之間幾乎完全相同。

現在,我承認C和C ++在處理寬字符串文字方面存在差異。

我能找到的唯一區別在於通過字符串文字初始化數組。

char str[3] = "abc"; /* OK in C but not in C++ */
char str[4] = "abc"; /* OK in C and in C++. Terminating zero at str[3] */

技術差異只在C ++中很重要。 在C ++中, "abc"const char [4]而在C中它是char [4] 但是,C ++有一個特殊的規則,允許轉換為const char * ,然后轉換為char *以保持C兼容性,直到C ++ 11不再應用該特殊規則。

文字允許長度的差異。 但是,實際上,編譯C和C ++代碼的任何編譯器都不會強制執行較低的C限制。

我有一些有趣的鏈接適用:

還有其他差異嗎?

原始字符串

一個明顯的區別是C ++的字符串文字是C語言的超集。 具體來說,C ++現在支持原始字符串 (在C中不支持 ),在技術上定義為§2.14.15,通常用於經常遇到" HTML和XML "

原始字符串允許您在表單中指定自己的分隔符(最多16個字符):

R"delimiter(char sequence)delimiter"

這對於通過提供自己的字符串分隔符來避免不必要的轉義字符特別有用。 以下兩個示例顯示了如何避免逃避"(分別:

std::cout << R"(a"b"c")";      // empty delimiter
std::cout << '\n';
std::cout << R"aa(a("b"))aa";  // aa delimiter
// a"b"c"
// a("b")

現場演示


char vs const char

注釋中指出的另一個區別是字符串文字在C中具有char [n]類型,如§6.4.5/ 6中所述:

對於字符串文字,數組元素的類型為char,並使用多字節字符序列的各個字節進行初始化。

而在C ++中,它們具有類型const char [n] ,如§2.14.5/ 8中所定義:

普通字符串文字和UTF-8字符串文字也稱為窄字符串文字。 窄字符串文字的類型為“n const char數組”,其中n是下面定義的字符串大小,並且具有靜態存儲持續時間(3.7)。

這並沒有改變這兩個標准(分別為C和C ++的§6.4.5/ 7和2.14.5 / 13)嘗試修改字符串文字導致未定義行為的事實。


未指定與實施定義( 參考

另一個細微的區別是,在C中,字符串文字的字符數組是不同的,未按照§6.4.5/ 7進行說明:

如果這些數組的元素具有適當的值,則這些數組是否不同是未指定的。

而在C ++中,這是實現定義,根據§2.14.5/ 13:

是否所有字符串文字都是不同的(即存儲在非重疊對象中)是實現定義的。

回答問題的最佳方法是將其重寫為在使用“C”或“C ++”編譯器時編譯相同的程序,我假設您正在使用GCC,但其他( 正確編寫的 )編譯器工具鏈應該提供類似的結果。

首先,我將解決您提出的每一點,然后我將提供一個程序,提供答案(和證明)。

  • 據我所知,在C ++ 11之前,字符串文字在C和C ++之間幾乎完全相同。

它們仍然可以使用各種命令行參數以相同的方式處理,在本例中我將使用“-fpermissive”(作弊)。 你最好找出為什么你會收到警告和編寫新代碼以避免任何警告; 只使用CLP'作弊'來編譯OLD代碼。

正確編寫新代碼 (沒有作弊和沒有警告,沒有錯誤就不用說了)。

  • 現在,我承認C和C ++在處理寬字符串文字方面存在差異。

沒有(許多差異),因為你可以根據具體情況欺騙大部分或全部。 作弊是錯誤的,學會正確編程並遵循現代標准而不是過去的錯誤(或尷尬)。 在某些情況下,事情以某種方式對您和編譯器都有幫助(請記住,您並不是唯一一個'看到'您的代碼的人)。

這種情況下,編譯器需要分配足夠的空間來終止帶有'0'(零字節)的String。 這允許使用print(和其他一些)函數而不指定String的長度。

如果你只是想編譯你從某個地方獲得的現有程序並且不想重寫它,你只需要編譯並運行它,然后使用作弊(如果你必須)通過警告和強制編譯成可執行文件。

  • 你寫的其余部分......

沒有。

請參閱此示例程序。 我稍微修改了你的問題,使其成為一個程序。 使用“C”或C ++“編譯器編譯本程序的結果是相同的。

將下面的示例程序文本復制並粘貼到名為“test.c”的文件中,然后按照開頭的說明進行操作。 只需“捕捉”文件,這樣您就可以在不打開文本編輯器的情況下對其進行反向滾動(並查看),然后從“編譯器命令”(接下來的三個)開始復制並粘貼每一行。

注意,正如評論中所指出的,運行此行“g ++ -S -o test_c ++。s test.c”會產生錯誤(使用現代g ++編譯器),因為容器不夠長,無法容納String。

您應該能夠閱讀本程序,而不是實際需要編譯它以查看答案,但它會編譯並生成輸出供您檢查,如果您希望這樣做。

正如您所看到的,Varable“str1”不足以在String終止時保存String,這會在現代(並且正確編寫)的g ++編譯器上產生錯誤。


/* Answer for: http://stackoverflow.com/questions/23145793/string-literal-differences-between-c-and-c
 *
 * cat test.c
 * gcc -S -o test_c.s test.c
 * g++ -S -o test_c++.s test.c
 * g++ -S -fpermissive -o test_c++.s test.c
 *
 */

char str1[3] = "1ab";
char str2[4] = "2ab";
char str3[]  = "3ab";

main(){return 0;}


/* Comment: Executing "g++ -S -o test_c++.s test.c" produces this Error:
 *
 * test.c:10:16: error: initializer-string for array of chars is too long [-fpermissive]
 * char str1[3] = "1ab";
 *                ^
 *
 */


/* Resulting Assembly Language Output */

/*      .file   "test.c"
 *      .globl  _str1
 *      .data
 * _str1:
 *      .ascii "1ab"
 *      .globl  _str2
 * _str2:
 *      .ascii "2ab\0"
 *      .globl  _str3
 * _str3:
 *      .ascii "3ab\0"
 *      .def    ___main;    .scl    2;  .type   32; .endef
 *      .text
 *      .globl  _main
 *      .def    _main;  .scl    2;  .type   32; .endef
 * _main:
 * LFB0:
 *      .cfi_startproc
 *      pushl   %ebp
 *      .cfi_def_cfa_offset 8
 *      .cfi_offset 5, -8
 *      movl    %esp, %ebp
 *      .cfi_def_cfa_register 5
 *      andl    $-16, %esp
 *      call    ___main
 *      movl    $0, %eax
 *      leave
 *      .cfi_restore 5
 *      .cfi_def_cfa 4, 4
 *      ret
 *      .cfi_endproc
 * LFE0:
 *      .ident  "GCC: (GNU) 4.8.2"
 *
 */

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM