ます’s Blog - どうでもいい記事100選

どうでもいい記事100選

PHPとPerlでビット演算(排他的論理和)

ある方からPerlPHPでビット演算子排他的論理和)の挙動が違うのは何で?って質問されました。
何で?って言われても???なのですが、気になったので調べてみました。

例:print bin2hex( ( "1234567890A" ^ "eda01110c533bf51e42c2390276eae11" ) );

Perl => 54565204040706085a0572336266353165343263323339303237366561653131
PHP => 54565204040706085a0572

動きを見る限りでは、Perlでは計算しない文字はそのまま返却しています。
それにに対し、PHPでは計算しない文字はカットして返却しているようでした。
(cvsが見えないので情報だけで勘弁を)

/(php-src dir)/Zend/zend_operators.c

ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
{
	zval op1_copy, op2_copy;
	
	if (op1->type == IS_STRING && op2->type == IS_STRING) {
		zval *longer, *shorter;
		char *result_str;
		int i, result_len;

		if (op1->value.str.len >= op2->value.str.len) {
			longer = op1;
			shorter = op2;
		} else {
			longer = op2;
			shorter = op1;
		}

		result->type = IS_STRING;
		result_len = shorter->value.str.len;
		result_str = estrndup(shorter->value.str.val, shorter->value.str.len);
		for (i = 0; i < shorter->value.str.len; i++) {
			result_str[i] ^= longer->value.str.val[i];
		}
		if (result==op1) {
			STR_FREE(result->value.str.val);
		}
		result->value.str.val = result_str;
		result->value.str.len = result_len;
		return SUCCESS;
	}

	zendi_convert_to_long(op1, op1_copy, result);
	zendi_convert_to_long(op2, op2_copy, result);	

	result->type = IS_LONG;
	result->value.lval = op1->value.lval ^ op2->value.lval;
	return SUCCESS;
}

どっちが正しいのかヨク分かりませんが、Perlと同じ挙動をするようにしてみました。
カナリ適当なタコさんパッチですが、勢いでっ。

--- php-4.4.0,orig/Zend/zend_operators.c	2005-09-07 10:53:34.000000000 +0900
+++ php-4.4.0/Zend/zend_operators.c	2005-09-07 10:53:34.000000000 +0900
@@ -959,10 +959,10 @@
 		}
 
 		result->type = IS_STRING;
-		result_len = shorter->value.str.len;
-		result_str = estrndup(shorter->value.str.val, shorter->value.str.len);
+		result_len = longer->value.str.len;
+		result_str = estrndup(longer->value.str.val, longer->value.str.len);
 		for (i = 0; i < shorter->value.str.len; i++) {
-			result_str[i] ^= longer->value.str.val[i];
+			result_str[i] ^= shorter->value.str.val[i];
 		}
 		if (result==op1) {
 			STR_FREE(result->value.str.val);

細かい部分の挙動の違いは仕方が無いんですけどねぇ。方言的なモンなんです、きっと。
しかしアレですね。zend_*_parser.*とか、zend_*_scanner.*とか見ると。。。
なんというか(できの悪い)テンプレート・エンジンを見ている錯覚が。。。流石に言い過ぎか。