strchr和strstr
突然发现strchr和strstr系列的函数接受const char *的参数却返回char *,这是不是意味着把const指针给HACK了,可以读写了?假设我通过这些函数查找一个const的字符串缓冲,然后通过返回的指针写入该缓冲,会发生什么事?? 接受const char*只不過是輸入唯讀,沒有人說const char*和 char*是相同的說
可能有這種結構
char* aaa(const char* input){
char* buffer = input;
//or
char* buffer;
buffer = copy_string(input);
//process...
return buffer;
}
這不就行嘛? 问题是一般编译器是不允许const xxx*向xxx*转换的,只允许xxx*向const xxx*转换(xxx*转换成const xxx*表示放弃写权限),所以
char* aaa(const char* input){
char* buffer = input;
编译是过不了的。
char* buffer;
buffer = copy_string(input);
//process...
return buffer;
这个倒是可能,但是strchr所得的指针是可以通过减运算得到与原指针相差的字符数的。
const char *str = "This is a string.";
char *pc = strchr(str,'h');
return pc-str;
这样是会返回1的,以前试过了。所以strchr应该不是使用复制缓冲区的方法实现,应该就是HACK了。 這個看來在486時代已經有定案了,找出一個asm-i486版本的string.h
查找了strchr, strstr依然是extern的,找不到
static inline char * strchr(const char * s, int c)
{
int d0;
register char * __res;
__asm__ __volatile__(
"movb %%al,%%ah\\n"
"1:\\tlodsb\\n\\t"
"cmpb %%ah,%%al\\n\\t"
"je 2f\\n\\t"
"testb %%al,%%al\\n\\t"
"jne 1b\\n\\t"
"movl $1,%1\\n"
"2:\\tmovl %1,%0\\n\\t"
"decl %0"
:"=a" (__res), "=&S" (d0)
:"1" (s),"0" (c)
:"memory");
return __res;
}
某還在解譯中 HACK指得是啥操作?
那个,编译不过可以写强制类型转换……const这种玩意儿只是编译期的约定吧,编译器保证标记了const的在函数体内不被改写,其实硬要改写也没办法,编译器还是很好骗的。
strstr这种接受了const char*返回char*是有点恶搞哦-_-b 投降了!某對GCC的內部絕望了,找來了MSVC 6 的strstr asm內解讀,看來一切已經超過了C
有注解好多了,一直只是使用不覺得有啥問題,給LZ一問呆了...
page ,132
title strstr - search for one string inside another
;***
;strstr.asm - search for one string inside another
;
; Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
;
;Purpose:
; defines strstr() - search for one string inside another
;
;*******************************************************************************
.xlist
include cruntime.inc
.list
page
;***
;char *strstr(str1, str2) - search for str2 in str1
;
;Purpose:
; finds the first occurrence of str2 in str1
;
;Entry:
; char *str1 - string to search in
; char *str2 - string to search for
;
;Exit:
; returns a pointer to the first occurrence of string2 in
; string1, or NULL if string2 does not occur in string1
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************
__from_strstr_to_strchr proto
CODESEG
publicstrstr
strstrproc
mov ecx, ; str2 (the string to be searched for)
push edi ; Preserve edi, ebx and esi
push ebx
push esi
mov dl, ; dl contains first char from str2
mov edi, ; str1 (the string to be searched)
test dl,dl ; is str2 empty?
jz empty_str2
mov dh, ; second char from str2
test dh,dh ; is str2 a one-character string?
jz strchr_call ; if so, go use strchr code
; length of str2 is now known to be > 1 (used later)
; dl contains first char from str2
; dh contains second char from str2
; edi holds str1
findnext:
mov esi,edi ; esi = edi = pointers to somewhere in str1
mov ecx, ; str2
;use edi instead of esi to eliminate AGI
mov al, ; al is next char from str1
inc esi ; increment pointer into str1
cmp al,dl
je first_char_found
test al,al ; end of str1?
jz not_found ; yes, and no match has been found
loop_start:
mov al, ; put next char from str1 into al
inc esi ; increment pointer in str1
in_loop:
cmp al,dl
je first_char_found
test al,al ; end of str1?
jnz loop_start ; no, go get another char from str1
not_found:
pop esi
pop ebx
pop edi
xor eax,eax
ret
; recall that dh contains the second char from str2
first_char_found:
mov al, ; put next char from str1 into al
inc esi
cmp al,dh ; compare second chars
jnz in_loop ; no match, continue search
two_first_chars_equal:
lea edi, ; store position of last read char in str1
compare_loop:
mov ah, ; put next char from str2 into ah
test ah,ah ; end of str2?
jz match ; if so, then a match has been found
mov al, ; get next char from str1
add esi,2 ; bump pointer into str1 by 2
cmp al,ah ; are chars from str1 and str2 equal?
jne findnext ; no
; do one more iteration
mov al, ; put the next char from str2 into al
test al,al ; end of str2
jz match ; if so, then a match has been found
mov ah, ; get next char from str1
add ecx,2 ; bump pointer in str1 by 2
cmp al,ah ; are chars from str1 and str2 equal?
je compare_loop
; no match. test some more chars (to improve execution time for bad strings).
jmp findnext
; str2 string contains only one character so it's like the strchr functioin
strchr_call:
xor eax,eax
pop esi
pop ebx
pop edi
mov al,dl
jmp __from_strstr_to_strchr
;
;
; Match!Return (ebx - 1)
;
match:
lea eax,
pop esi
pop ebx
pop edi
ret
empty_str2: ; empty target string, return src (ANSI mandated)
mov eax,edi
pop esi
pop ebx
pop edi
ret
strstrendp
end
某的解譯大約昰這樣
mov edi, ; str1 (the string to be searched)
edi是內部次理用的存址,是str1
基本上在這個mov之後,便沒有被存取
也就是說原地址(esp + 10h),只有讀的份,便滿足const協定
edi在程序中是有讀寫部份
lea edi,
讀不寫,自己找吧
而傳回值eax相關指令部份
xor eax,eax 只是把xor eax,eax清0,不多說
lea eax,
mov eax,edi
這兩個也只是讀取edi,其實便是包了把結果經bufer存到edi,再傳回eax
也就是
const char* char*
>>> edi >>> eax
這感覺
換句話,用C/C++語法就是
char* aaa(const char* input){
char* buffer = input;
//process...
return buffer;
}
的structure 引用第4楼FantasyDR于2007-08-30 00:50发表的:
HACK指得是啥操作?
那个,编译不过可以写强制类型转换……const这种玩意儿只是编译期的约定吧,编译器保证标记了const的在函数体内不被改写,其实硬要改写也没办法,编译器还是很好骗的。
strstr这种接受了const char*返回char*是有点恶搞哦-_-b
的確是協定,但問題是在於這個協定是如何做到,上面某想是最完整的解釋了。。。 引用第4楼FantasyDR于2007-08-30 00:50发表的:
HACK指得是啥操作?
那个,编译不过可以写强制类型转换……const这种玩意儿只是编译期的约定吧,编译器保证标记了const的在函数体内不被改写,其实硬要改写也没办法,编译器还是很好骗的。
strstr这种接受了const char*返回char*是有点恶搞哦-_-b
记得强制转换也是不行的,以前试过了。不过可以先转成unsigned int再转,所以也不成问题……
HACK是指把本来不允许的变允许了,这个用词纯粹道听途说……
我也知道这个函数是汇编写的,汇编是没有const这概念,所以绝对可行。
经过测试,也参照coolpay64的代码,strchr只是把const char*偷换成char *罢了,内存页的属性还是没有变的,用只读内存的指针调用strchr,返回的指针还是不能写,不过不是编译器提醒,而是直接runtime error。如果用读写内存指针调用就相安无事。
const char *str = "This is test."; /* str指向程序的字符串池,只读内存 */
char *pc = strchr(str, 'h');
*pc = 0; /* 访问违规 */
const char str[] = "This is test."; /* str指向系统栈,读写内存 */
char *pc = strchr(str, 'h');
*pc = 0; /* 通过,产生预期结果 */
我的理解是C不支持函数重载,所以返回char *以保证兼容const char *和char *,返回的指针能怎么用还要靠自我认识。 这些貌似在新版本的编译器上面有部分改动了……
偶印象中这样的,因为在编译的时候会有二个版本出现:
const char* + const char*
char* + char*
但忘了是不是给这些函数用的………………
总之C下面const可以是无视掉的XD
页:
[1]