ホームページ >バックエンド開発 >Python チュートリアル >Python が C SDK を呼び出したときの戻り値が期待を満たさない場合とセグメンテーション違反の解決策

Python が C SDK を呼び出したときの戻り値が期待を満たさない場合とセグメンテーション違反の解決策

高洛峰
高洛峰オリジナル
2017-03-20 11:04:102059ブラウズ

1. SDKの戻り値はint型ではありません

1.1 ログイン関数call

def login(ip, port, username,password, device_info, error_code):
"""
LLONG CLIENT_Login(
) char *pchDVRIP , WORD wDVRPort,
char *pchUserName, char *pchPassword,
LPNET_DEVICEINFO lpDeviceInfo, int *error = 0);
:param ip:
:param port:
: パラメータ ユーザー名:
:param パスワード:
:param device_info:
:param error_code:
:return: LLONG
"""
ip_buffer = c_buffer(ip )
# ip_buffer.encode('utf8')
# user_id = c_longlong(0)
user_id = SDK._dll.CLIENT_Login(byref(ip_buffer), ポート, ユーザー名, パスワード, byref(device_info), byref (error_code) )
return user_id # c_longlong(user_id).value

1.2 無効な ID

ユーザー ID がハンドルとして使用され、他の SDK 関数に渡されます。エラーが報告され、ハンドルは無効です。 。負の値をチェックします。したがって、型の不一致が疑われます

Python调用C的SDK出现返回值不符合预期以及Segmentation fault的解决方法

1.3 戻り値の型の設定

1.3.1 エラーの原因

PythonでCのSDKを呼び出すときにオンラインで調べてドキュメントを読みました。 、デフォルトの戻り値は int 型で、ログイン C バージョンの関数定義に従って、LLONG 型を返します

15.17.1.8。戻り値の型

デフォルトでは、関数は C の int を返すと想定されています。 code> タイプ。他の戻り値の型は、関数 <a href="http://www.php.cn/wiki/60.html" target="_blank">restype</a> 属性を設定することで指定できます。 ">objectint type. Other return types can be specified by setting the restype attribute of the function object.

Here is a more advanced example, it uses the strchr.これはより高度な例です。strchr 関数を使用します。この関数は

string

ポインタと char を期待し、文字列へのポインタを返します:

>>> strchr = libc.strchr
>>> strchr("abcdef", ord("d"))  
8059983
>>> strchr.restype = c_char_p   # c_char_p is a pointer to a string
>>> strchr("abcdef", ord("d"))
'def'
>>> print strchr("abcdef", ord("x"))
None
>>>

1.3 .2 set sdk

関数を修正 戻り値

がc_longlongになり、問題は解決

SDK._dll.CLIENT_Login.restype = c_longlong

2,

Callback function

シナリオでは高確率でセグメンテーション違反

オンラインで検索したところ、2 つの可能性が見つかりました。メモリが範囲外であるか、読み取りまたは書き込みが不正です。もう 1 つは、関数呼び出しスタックが深すぎることです。

2.1 読み取り/書き込みロック

コード自体は条件読み取り/書き込みロックを追加し、書き込み時に buf も割り当てられます。デバッグを繰り返した後、ここで問題になることはありません。ログを出力すると、それが読み取りおよび書き込み操作とは関係がないことがわかります。

Write

index = userdata  # c_uint(userdata).value
_buf_cond.acquire()
# time.sleep(0.2)

# 复制图片到内存
# _pic_buf.buf = pBuf  c_char 和 c_byte转换
try:
    temp = [pBuf[i] for i in xrange(0, RevLen)]
    _buf_list[index].buf = struct.pack('%db' % RevLen, *temp)
    # 序列号
    _buf_list[index].sn = c_ulong(CmdSerial).value
    _buf_list[index].id = index
    _buf_list[index].size = c_uint(RevLen).value
    _buf_list[index].ext = 'jpeg'  # encode_dict.get(EncodeType, 'jpeg')
except Exception, e:
    logger.error('截图缓存发生异常:%s' % str(e))
finally:
    _buf_cond.notify()
    _buf_cond.release()
_buf_cond.acquire()
_buf_cond.wait(timeout=15.0)
# 等待200ms再访问数据
# time.sleep(0.2)
if _buf_list[self.index].sn == snap.CmdSerial and _buf_list[self.index].id == self.index:
    self.save_picture(_buf_list[self.index].buf, _buf_list[self.index].ext)
    self.info('针对通道%d截图成功,IP:%s,Port:%s' % (channel, self.ip, self.port))
    pass
_buf_cond.release()

2.2 スタックコールレベルを下げる

このSDKの導入により、コールバック関数が使用されます。そのため、コールバック関数の定義レベルが下がります。

2.2.1 修正前

関数を基底クラスに渡し、基底クラスで関数 CFUNCTYPE をインスタンス化

基底クラスに定義する

self.callback = CFUNCTYPE(c_void_p, c_longlong, POINTER(c_byte), c_uint, c_uint, c_ulong, c_ulonglong)
def set_callback(self, save_after_recv_pic, index):
    self.dll.CLIENT_SetSnapRevCallBack(self._callback(save_after_recv_pic), index)
rreeerrreerree
子类中定义,_save_after_recv_pic也在子类中定义为staticmethod

2.2.2 修正後、問題は解決します

🎜 サブクラスのコールバック関数で直接インスタンス化する 🎜
def _set_callback(self):
    try:
        if 0 <= self.index < _buf_size:
            self.set_callback(self._save_after_recv_pic, self.index)   # 函数调用层次太深,经常报segmentation fault
            return True
        else:
            self.error('设置截图保存回调函数的userdata参数错误:%d' % self.index)
            return False
    except Exception, e:
        self.error('设置截图保存回调函数失败,%s' % str(e))
        return False
 <br>

以上がPython が C SDK を呼び出したときの戻り値が期待を満たさない場合とセグメンテーション違反の解決策の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。