3

SPI インターフェイスにアクセスするために、C で PHP 拡張機能を作成しています。これまでのところ、ほとんどすべてが機能しています: Github の php_spi

ただし、コンストラクターの $options パラメーターをオプションにすることはできないようです。私の作業コードは次のようなものです:

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lla", &bus, &chipselect, &options) == FAILURE) {
    return;
}

_this_zval = getThis();
_this_ce = Z_OBJCE_P(_this_zval);

options_hash = HASH_OF(options);

char device[32];
sprintf(device, "/dev/spidev%d.%d", bus, chipselect);

// If the device doesn't exists, error!
if(access(device, F_OK) == -1) {
    char error[128];
    sprintf(error, "The device %s does not exist", device);
    php_error(E_ERROR, error);
}

// If we can't open it, error!
long fd = open(device, O_RDWR);
if (fd < 0) {
    char error[128];
    sprintf(error, "Could not open %s for read/write operations, are you running as root?", device);
    php_error(E_ERROR, error);
}

// Set the file descriptor as a class property
zend_update_property_long(_this_ce, _this_zval, "device", 6, fd TSRMLS_DC);

// Default property values
uint8_t mode = SPI_MODE_0;
uint8_t bits = 8;
uint32_t speed = 500000;
uint16_t delay = 0;

// Loop through the options array
zval **data;
for(zend_hash_internal_pointer_reset(options_hash);
    zend_hash_get_current_data(options_hash, (void **)&data) == SUCCESS;
    zend_hash_move_forward(options_hash)) {

    char *key;
    int len;
    long index;
    long value = Z_LVAL_PP(data);

    if(zend_hash_get_current_key_ex(options_hash, &key, &len, &index, 1, NULL) == HASH_KEY_IS_STRING) {
        // Assign the value accordingly
        if(strncmp("mode", key, len) == 0) {
            switch(value) {
                case SPI_MODE_1:
                    mode = SPI_MODE_1;
                    break;
                case SPI_MODE_2:
                    mode = SPI_MODE_2;
                    break;
                case SPI_MODE_3:
                    mode = SPI_MODE_3;
                    break;
                default:
                    mode = SPI_MODE_0;
                    break;
            }
        }
        else if(strncmp("bits", key, len) == 0) {
            bits = value;
        }
        else if(strncmp("speed", key, len) == 0) {
            speed = value;
        }
        else if(strncmp("delay", key, len) == 0) {
            delay = value;
        }
    }
}

ただし、すべてのドキュメントの提案に従うと、次のように l と a の間にパイプを見つけて追加できます。

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll|a", &bus, &chipselect, &options) == FAILURE) {

その後、私の拡張機能は黙って失敗します - 誰かアドバイスをもらえますか?

4

1 に答える 1

4

これを行う場合、optionsは であると仮定します。zval*

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll|a", &bus, &chipselect, &options) == FAILURE) {
    return;
}

...optionsが渡されない場合 (つまり、3 番目のオプション引数を省略した場合)、options初期化も変更もされません。後で、次のようにします。

options_hash = HASH_OF(options);

したがって、初期化されていないポインター、または未定義の動作である NULL ポインターを使用しています。これにより、セグメンテーション違反が発生し、PHP スクリプトが失敗する可能性があります。

あなたがすべきことは次のようなものです:

zval* options = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll|a", &bus, &chipselect, &options) == FAILURE) {
    return;
}

// ...

if (options != NULL) {
    options_hash = HASH_OF(options);
}

options...そして(and )のすべてのインスタンスをoptions_hash、それがそうであるかどうかをチェックする条件で処理しますNULL

于 2012-08-25T22:26:21.783 に答える