用于丑陋的C结构分配的现代C ++模式

时间:2016-06-27 22:56:26

标签: c c++11

我正在从C ++调用ioctl调用一个我不拥有/维护的驱动程序,而我正试图弄清楚是否有一个干净的,“安全的”机制来处理一些需要的丑陋结构分配。

涉及一些结构的简化版本

// IOCTL expects an instance of this structure "first"
typedef struct {
   int param1;
   int param2;
} s_ioctl_request;

//... followed by an instance of this.  If attr_length
// is > sizeof(s_attr_header), more data is allowed to follow.
typedef struct {
   uint32_t attr_length;
   uint32_t attr_type;
} s_attr_header;

// Example that uses more data than just the header.
typedef struct {
   s_attr_header   hdr;
   uint32_t attr_param;
} s_attr_type1;

// Another example.
typedef struct {
   s_attr_header   hdr;
   uint32_t attr_param1;
   uint32_t attr_param2;
} s_attr_type2;

ioctl要求s_ioctl_request后面紧跟s_attr_header或其他包含它的结构,其中attr_length设置为外部结构的大小(以字节为单位)。

C中,要为ioctl编写包装器,可以通过以下方式完成:

int do_ugly_ioctl(int fd, int p1, int p2, s_attr_header * attr)
{  
   int res;      
   // Allocate enough memory for both structures.
   s_ioctl_request *req = malloc( sizeof(*req) + attr->hdr.attr_length );

   // Copy the 2nd, (variable length) structure after the first.
   memcpy( ((char*)req) + sizeof(*req), attr, attr->hdr.attr_length);

   // Modify params as necessary
   req->param1 = p1;
   req->param2 = p2;

   // Make the driver call, free mem, and return result.
   res = ioctl(fd, SOME_IOCTL_ID, req);
   free(req);
   return res;
}

// Example invocation.
s_attr_type1 a1;
a1.hdr.attr_length = sizeof(a1);
a1.hdr.attr_type   = 1;
do_ugly_ioctl(fd, 10, 20, &a1);

我想到的几个选项是:

  1. 抛出现代C ++ - 窗外的主义,并完全按照我上面所示的那样做。

  2. 使用std :: vector分配存储,然后使用生成的std :: vector :: data()指针进行丑陋的转换,这样至少我没有new[] / {{1 }}或delete[] / malloc

  3. 为使用自己的“特殊”结构的每个free创建一个唯一的包装器方法。这似乎是“最安全的”,即包装方法的用户最不可能将其搞砸。和奖励积分,允许传递参考。

  4. 方法#3示例:

    s_attr_type*

    所以我想这里的一些问题是:

    • 对C ++来说“值得吗” - 找到解决这个问题的方法吗? (而不是依赖于更易出错的C impl)。

    • 如果我使用方法#3或类似方法,我可以使用int do_ugly_ioctl(fd, int param1, int param2, s_attr_type2& attr){ struct RequestData { s_ioctl_request ioreq; s_attr_type2 attr; }; RequestData r; r.ioreq.param1 = param1; r.ioreq.param2 = param2; r.attr = attr; r.attr.hdr.attr_length = sizeof(attr); // Might as well enforce this here. ioctl(fd, SOME_IOCTL_ID, (void*) &r); } 制作此函数的模板,并仅接受<type_traits>作为第一个的结构构件?

    • 还有其他精彩的想法吗?

1 个答案:

答案 0 :(得分:3)

完全值得,你的解决方案非常好。 您可能希望将结构声明为import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.*; public class TimerPanel extends JPanel{ private int min,sec; private String theTime = min + ":" + sec; private int width=350, height=300; private boolean timerStarted=false; private Timer swingTimer = new Timer(900, new ActionListener(){ public void actionPerformed(ActionEvent event){ if(sec<60){ sec++; repaint(); }else{ min++; sec=0; repaint(); } } }); //Constructor public TimerPanel(){ setPreferredSize(new Dimension(350,300)); } //------------------------------------------------------------------------------------------------------------------------------------------------------------------------ //start the timer public void startTimer(){ swingTimer.start(); } //Stop the timer public void stopTimer(){ swingTimer.stop(); } //reset the timer public void resetTimer(){ sec=0; min=0; repaint(); } //------------------------------------------------------------------------------------------------------------------------------------------------------------------------ //Paint Method public void paintComponent(Graphics g){ super.paintComponent(g); g.setColor(Color.WHITE); g.setFont(new Font("Arial", Font.PLAIN, 40)); g.drawString(theTime, width/2-45, height/2); setBackground(Color.BLACK); } //------------------------------------------------------------------------------------------------------------------------------------------------------------------------ } (有实现此目的的编译器扩展),以避免在组合多个结构时有额外的填充。

您还可以在构造函数中设置结构的大小。

packed

关于你的第二个问题,你可以将赋值分成两部分,它不是太好但是很容易,如果你传递的东西没有正确的标题,就会导致编译错误:

struct RequestData
{
      RequestData() : ioreq{}, attr{}
      {
        attr.hdr.attr_length =  sizeof(attr);
      }
      s_ioctl_request ioreq;
      s_attr_type2    attr;
 };