编程时,一次又一次地存储相同的常量数据可能是一种浪费。您使用更多内存,访问更多数据。值得庆幸的是,您的优化编译器可能会有所帮助。
考虑以下两行 C 代码:
printf ( “琼斯教授晚安” ) ;
printf ( “简教授你好” ) ;
由于前缀“Good day Professor”在两种情况下都是相同的,因此存在冗余。据我所知,没有编译器可能会削减这种冗余。但是,您可以通过断开字符串来获得所需的修剪:
printf ( “教授你好” ) ; printf ( "琼斯" ) ; printf ( “教授你好” ) ; printf ( "简" ) ;
大多数编译器将识别常量字符串并将其存储在程序中一次。即使常量字符串“Good day Professor”出现在不同的函数中,它也可以工作。
因此,以下函数可能返回 true:
const char * str1 = "亲爱的朋友" ; const char * str2 = "亲爱的朋友" ; 返回str1 = = str2 ;
也就是说,您不需要手动创建常量字符串:编译器会识别冗余(通常)。
扩展字符串同样的技巧失败了:
const char * str1 = "亲爱的朋友" ; const char * str2 = "亲爱的朋友\0 f " ; 返回str1 = = str2 ;
我尝试过的所有编译器都返回 false。他们创建两个 C 字符串,即使在以下示例中一个是另一个的前缀…
字符get1 ( int k ) { const char * str = "亲爱的朋友" ; 返回str [ k ] ; } char get2 ( int k ) { const char * str = "亲爱的朋友\0 f " ; 返回str [ k ] ; }
不出所料,“数据压缩”技巧适用于数组。例如,这两个函数中的数组很可能只编译为一个数组,因为编译器认为它们是相同的:
诠释f (诠释k ) { int数组[ ] = { 1 , 2 , 3 , 4 , 5 , 34432 , 321323 , 321321 , 1 , 2 , 3 , 4 , 5 , 34432 , 321323 , 321321 } ; 返回数组[ k ] ; } 诠释克(诠释克) { int数组[ ] = { 1 , 2 , 3 , 4 , 5 , 34432 , 321323 , 321321 , 1 , 2 , 3 , 4 , 5 , 34432 , 321323 , 321321 } ; 返回数组[ k + 1 ] ; }
如果一个数组是使用 GCC 的另一个数组的精确子数组,它可能仍然有效,如下例所示:
诠释f (诠释k ) { int数组[ ] = { 1 , 2 , 3 , 4 , 5 , 34432 , 321323 , 321321 , 1 , 2 , 3 , 4 , 5 , 34432 , 321323 , 321321 } ; 返回数组[ k ] ; } 诠释克(诠释克) { int数组[ ] = { 1 , 2 , 3 , 4 , 5 , 34432 , 321323 , 321321 , 1 , 2、3、4、5、34432、321323、321321、1、4 } ; _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 返回数组[ k + 1 ] ; }
它也适用于指针数组,如下例所示:
const char * get1 ( int k ) { const char * str [ ] = { “亲爱的朋友” 、 “亲爱的姐姐” 、 “亲爱的兄弟” } ; 返回str [ k ] ; } const char * get2 ( int k ) { const char * str [ ] = { “亲爱的朋友” 、 “亲爱的姐姐” 、 “亲爱的兄弟” } ; 返回str [ k + 1 ] ; }
当然,如果你想确保你的代码保持精简和高效,你不应该盲目地依赖编译器。尽管如此,还是有理由略微乐观。
原文: https://lemire.me/blog/2022/09/23/optimizing-compilers-deduplicate-strings-and-arrays/