Ошибки ctypes с argv - PullRequest
       16

Ошибки ctypes с argv

2 голосов
/ 28 октября 2019

Я пытаюсь вызвать библиотеку C ++ из python с типами, но я не могу передать в качестве аргументов IP и HEX-код, кто-нибудь может мне помочь?

import sys 
import ctypes 

lib = ctypes.CDLL('./hello.so') 

LP_c_char = ctypes.POINTER(ctypes.c_char) 
LP_LP_c_char = ctypes.POINTER(LP_c_char) 

lib.connect_pe_func.argtypes = (ctypes.c_int, LP_LP_c_char)  

argc = 2
argv = ["192.168.2.170","2600000026"]
for i, arg in enumerate(sys.argv): 
  enc_arg = arg.encode('utf-8') 
  argv[i] = ctypes.create_string_buffer(enc_arg) 

lib.connect_pe_func(argc, argv)

это ошибкасообщение, как мне вставить IP и шестнадцатеричный код в вектор argv без этой ошибки?

---------------------------------------------------------------------------
ArgumentError                             Traceback (most recent call last)
<ipython-input-21-f59eabe02690> in <module>
     17   argv[i] = ctypes.create_string_buffer(enc_arg)
     18
---> 19 lib.connect_pe_func(argc, argv)

ArgumentError: argument 2: <class 'TypeError'>: expected LP_LP_c_char instance instead of list

для полноты я также вставляю код C ++, который я скомпилировал и сделал в библиотеку hello.so

#include <stdio.h>
#include <errno.h>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <cstring>
#include <unistd.h>
#include <iostream>
#include <unistd.h>
#include <sstream>
#include "connect_PE_func.h"
using namespace std;


extern "C" char * connect_pe_func(int argc, char *argv[])
{
    int sockfd, n;
    int connected = 0;
    struct sockaddr_in servaddr;
    std::string serveraddr = argv[1];

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr(serveraddr.c_str());
    servaddr.sin_port = htons(9761);

    connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    std::string pref_hex;
    std::string hex("0x");
    std::string test = argv[2];
    size_t numbytes = test.size() / 2;

    uint8_t command[numbytes];

    for (size_t w = 0, x = 0; w < numbytes; ++w, x += 2)
    {
        pref_hex = hex + test.substr(x, 2);
        cout << pref_hex;
        command[w] = stoi(pref_hex, nullptr, 16);
    }

    int bytes_to_send = sizeof(command);

    send(sockfd, command, bytes_to_send, 0);
    uint8_t output_command[numbytes];
    recv(sockfd, output_command, bytes_to_send, 0);

    char test_out[10];

    for (size_t w = 0, x = 0; w < numbytes; ++w, x += 2)
    {
        test_out[x] = (char)output_command[w];
    }
    return test_out;
};

extern "C" char * hello_world(char * name){
    char * output = (char *) calloc(sizeof(name)+7, sizeof(char));
    strcat(output, "Hello ");
    strcat(output, name);
    strcat(output, "\0");
    //output[sizeof(output)-1] = '/0';
    return output;

};

1 Ответ

1 голос
/ 29 октября 2019

Списки Python не могут быть переданы как указатели указателей.

Чтобы создать и заполнить указатель указателей из Python, вам необходимо:

  • для создания указателя массив : p = (LP_c_char*len(argv))() (выделяет пространство для указателей)
  • до приведение в указатель указателей: na = ctypes.cast(p, LP_LP_c_char) (делает его совместимым с затухшим указателемформа указателей)

или без переопределений:

p = (ctypes.POINTER(ctypes.c_char)*len(argv))()
na = ctypes.cast(p, ctypes.POINTER(ctypes.POINTER(ctypes.c_char)))

Исправлен код:

import sys
import ctypes

lib = ctypes.CDLL('./hello.so')

LP_c_char = ctypes.POINTER(ctypes.c_char)
LP_LP_c_char = ctypes.POINTER(LP_c_char)

lib.connect_pe_func.argtypes = (ctypes.c_int, LP_LP_c_char)

argv = ["192.168.2.170","2600000026"]
argc = len(argv)

p = (LP_c_char*len(argv))()
for i, arg in enumerate(argv):  # not sys.argv, but argv!!!
  enc_arg = arg.encode('utf-8')
  p[i] = ctypes.create_string_buffer(enc_arg)

na = ctypes.cast(p, LP_LP_c_char)

lib.connect_pe_func(argc, na)

Чтобы проверить это, я создал очень простой c ++код (вместо вашего)

#include <stdio.h>

extern "C" char * connect_pe_func(int argc, char *argv[])
{
   for (int i=0;i<argc;i++)
   {
      puts(argv[i]);
   }
   return 0;
}

, созданный с помощью: g++ -shared -o hello.so test.cpp

, запускающий модуль python, доказывает, что аргументы передаются правильно:

192.168.2.170
2600000026

Вдохновлен Указатели и массивы в Python ctypes

...