C测试变量是否在只读部分

我想编写一个低级日志记录function,如下所示:

DO_DBG("some string", val1, val2) 

我想要它做的是,出于性能原因,将指针存储到字符串而不是字符串的副本。 这假定该字符串是只读文字。 为了防止人们不得不调试调试器,如果DO_DBG的第一个参数是在代码与文本等的可写部分中,那么编译器会抱怨会很好。我想知道是否存在这样做的机制。 (我正在使用gcc 4.9.1,ld 2.24)。

您可以使用自动文字字符串连接来获得优势:

 #define DO_DBG(s, a, b) _DO_DBG("" s, a, b) 

并将您的真实宏实现为_DO_DBG

您可以设置SIGSEGV处理程序,然后尝试执行以下操作:

 s[0] = s[0]; 

如果处理程序被触发,则意味着该变量位于只读段中,因此您可以保存指针。 如果没有,您可以投诉(或只是复制字符串)。

您需要声明字符串volatile以便编译器不会优化分配。

或者,您可以使用stringify宏构造:

 #define DO_DBG(s, a, b) DO_DBG_INTERNAL(# s, a, b) 

并调用你的函数DO_DGB_INTERNAL所以人们会这样做:

 DO_DBG(some string, val1, val2) 

PS,很可能是一个可变函数和宏在这里是个好主意。

您的函数获取指向字符串开头的指针。 如果您的操作系统允许它,并且编译器以这种方式设置它,则可以在只读存储器区域中分配常量字符串(如示例中所示)。 如果您的编译器是智能的,它将存储一个出现多次的字符串常量的副本。 它甚至可能会发现某些字符串从未被使用过,而根本就没有存储它们。

除了上述内容之外,除非您的程序依赖于未定义的行为(在常量字符串上写入),否则您应该无法确定它是否在只读内存中。 您可以比较字符串的地址,看它们是否只是一个副本,但就是这样。

在任何合理的 C实现中(也就是说,只是为了让你搞砸了),如果字符串是只读的,那么你将看不到(或者至多是极小的)性能差异,读写,一份或几份。

如果你用char *参数编写函数,并将指针存储起来(不是复制到指向的字符串),你应该总是得到相同的字符串(除非你的环境真的很奇怪)。

这是一个基于SIGSEGV处理程序的测试,用于检查指向的内存是否以只读方式映射:

 #define _GNU_SOURCE #include  #include  #include  #include  static sigjmp_buf label; static void segv_hndlr(int Sig) { siglongjmp(label,1); } //safe in this ctx _Bool is_ro(char volatile *X) { _Bool r=0; struct sigaction old; X[0]; //fault now if the target isn't writable if(sigsetjmp(label,1)) { r=1; goto out; } sigaction(SIGSEGV,&(struct sigaction){.sa_handler=segv_hndlr}, &old); X[0]=X[0]; out: sigaction(SIGSEGV,&old, NULL); return r; } //example: int main() { #define PR_BOOL(X) printf(#X"=%d\n", X) char bar[]="bar"; char *baz = strdup("baz"); static int const static_ro_int = 42; int const auto_ro_int = 42; PR_BOOL(is_ro("foo")); //1 PR_BOOL(is_ro(bar)); //0 PR_BOOL(is_ro(baz)); //0 PR_BOOL(is_ro((void*)&static_ro_int)); //1 PR_BOOL(is_ro((void*)&auto_ro_int)); //0 }