【问题标题】:Resizing a char[x] to char[y] at runtime在运行时将 char[x] 调整为 char[y]
【发布时间】:2009-07-20 13:31:14
【问题描述】:

好的,我希望我能正确解释这一点。 我有一个结构:

typedef struct _MyData
{
   char Data[256];
   int  Index;
} MyData;

现在,我遇到了一个问题。大多数时候 MyData.Data 可以使用 256,但在某些情况下,我需要将它可以容纳的字符数量扩展到不同的大小。 我不能使用指针。 有没有办法在运行时调整数据大小?如何? 代码表示赞赏。

谢谢

编辑:

虽然我非常感谢所有的 cmets,但“也许试试这个……”或“那样做”,或者“你是错的……” cmets 没有帮助。代码是这里的帮助。如果您知道答案,请发布代码。

和:

1- 不能使用指针。请不要试图找出原因,我就是不知道 2- 结构被注入到另一个程序的内存中。这就是为什么。没有指针。

很抱歉在这里有点粗鲁,但我在这里问了这个问题,因为我已经尝试了所有认为可能有效的不同方法。 同样,我正在寻找代码。在这一点上,我对“可能工作......”或“你考虑过这个......”不感兴趣

谢谢你,我再次道歉

编辑 2

为什么设置为已回答?

【问题讨论】:

  • 为什么不能使用指针?动态分配数组是做到这一点的唯一方法。
  • 要么为任何数据输入静态保留足够的空间,要么您必须使用指针来动态分配空间。真的没有其他选择。
  • 你已经在使用指针了:P
  • 数组的好处是它们没有指向数据。因此,如果您将一个数组放入您的结构中,数据将从数组开始的位置开始,从而允许将结构 + 包含在其中的数组视为一个可以来回发送的单个单元。如果你在那里放置一个指针,这将中断。您应该将自己从将数组视为指针的情况中解脱出来。你可以写char *ptr = array; 并不代表什么:你也可以写char *ptr = 0;,但整数和指针仍然是两个主要的不同的东西。
  • 建议使用指针。 char Data[]; 不是指针。你在哪里看到我在我的主要推荐中提出了一个指针?好吧,没有冒犯,但我也完成了这个问题,直到你问一些更有意义的问题。我不会编写多线程+分布式应用程序只是为了向您展示它的工作原理。

标签: c resize char


【解决方案1】:

您可以使用灵活的数组成员

typedef struct _MyData
{
   int  Index;
   char Data[];
} MyData;

这样你就可以分配合适的空间

MyData *d = malloc(sizeof *d + sizeof(char[100]));
d->Data[0..99] = ...;

稍后,您可以释放并分配另一块内存并将指向MyData 的指针指向它,此时您将在灵活数组成员(realloc)中拥有更多/更少的元素。请注意,您也必须在某处保存长度。

在 C99 之前的时代,没有灵活的数组成员:char Data[] 被简单地视为类型不完整的数组,编译器会为此抱怨。在这里,我向您推荐两种可能的方法

  • 使用指针:char *Data 并使其指向分配的内存。这不像使用嵌入式数组那样方便,因为您可能需要进行两次分配:一个用于结构,另一个用于指针指向的内存。如果您的程序中的情况允许,您也可以在堆栈上分配结构。
  • 改为使用char Data[1],但将其视为更大,以便覆盖整个分配的对象。这是形式上未定义的行为,但它是一种常用技术,因此与您的编译器一起使用可能是安全的。

【讨论】:

  • 您为什么将其设置为答案?它不起作用。它崩溃了。
  • 我正在使用一个字符数组,因为我不能使用指针。所以这个解决方案不是一个有效的解决方案。但是无所谓。有你的方式感谢您的帮助
  • @wonderer,这个答案会出现什么问题?它推荐一个数组(“char Data[];”)。你接受了这个答案,不接受其他任何东西,而不是其他任何人:) 请询问我的回答是否有任何不清楚的地方,我会看看我们能做些什么。
  • 正如我在问题和后续 cmets 中所写,我不能使用任何类型的指针。原因(再次)是因为我将该结构传递到另一个进程内存中,所以我无法访问指针指向的数据。你还要我解释什么?
  • 我没有看到我建议您在哪里使用指针进行进程间通信。第二个项目符号和主要建议都使用数组,第一个项目符号是在您提出不能使用指针之前编写的。我想让你解释 1) 它是如何崩溃的 2) 为什么你一直告诉我你不能使用指针。除非你告诉我,否则我什么都做不了。
【解决方案2】:

这里的问题是您的陈述“我不能使用指针”。您将不得不这样做,这将使一切变得更加容易。嘿,realloc 甚至会复制你现有的数据,你还想要什么?

那么为什么你认为你不能使用指针呢?最好尝试解决这个问题。

【讨论】:

  • +1,没有指针就无法做到这一点。只能使用 malloc、realloc 等来完成。真正的问题是为什么没有指针。
  • 因为我将该数据传递给另一个进程,并且所有内容都必须位于该结构中。一个我传递了该数据,另一个进程必须有权访问它,并且我不能使用指针。这两个进程不共享内存。我只是在该结构中使用指针时崩溃。
  • @wonderer,每个 IPC 机制都有一些方法可以传递可变数量的数据。您应该研究如何使用您使用的任何机制来做到这一点。
  • 问题是我们正在处理一个不再受支持的程序,所以我发现执行某些代码的唯一方法是通过 DLL 注入。注入基本上是在对程序的主调用执行之后执行的,并且一旦在“旧版”软件中执行某个功能,它也会执行注册表清理。我需要传递结构中包含的所有数据,否则注入的程序(遗留软件)将不知道它们在哪里。
  • @wonderer:按照 litb 的建议去做;您注入的代码只需要知道结构的开始位置。
【解决方案3】:

你会像那样重新安排结构

typedef struct _MyData
{
   int  Index;
   char Data[256];
} MyData;

然后像这样使用 malloc/realloc 分配实例:

my_data = (MyData*) malloc ( sizeof(MyData) + extra_space_needed );

这是一种丑陋的方法,我不会推荐它(我会使用指针),但可以回答你的问题如何在没有指针的情况下进行操作。

一个限制是每个结构只允许一个可变大小的成员,并且必须在末尾。

【讨论】:

  • 是的,这可行,但您可能会遇到很多问题。例如,sizeof(MyData) 不再一定是正确的,因此默认的按值复制操作会将 Data 截断为 256 个字节。
  • 如果这应该是C,不要转换malloc的返回值。 c-faq.com/malloc/mallocnocast.html
【解决方案4】:

让我总结一下我在这个帖子中看到的两个重点:

  1. 该结构用于两个程序之间通过某种IPC机制进行交互
  2. 无法更改目标程序

因此,您无法以任何方式更改该结构,因为目标程序在尝试按照当前定义的方式读取它时卡住了。恐怕你被困住了。

您可以尝试找到获得等效行为的方法,或者找到一些邪恶的 hack 来强制目标程序读取新结构(例如,修改可执行文件中的二进制偏移量)。这都是非常具体的应用程序,所以我不能提供比这更好的指导了。

您可以考虑编写第三个程序作为两者之间的接口。它可以接收“长”消息并对其进行处理,然后将“短”消息传递给旧程序。您可以很容易地在 IPC 机制之间注入它。

【讨论】:

  • @wonderer:其实一直以来都是你犯了大错。这是您问题的唯一答案-您所要求的不可能做到。您应该已将 Chris 的答案标记为正确答案。
【解决方案5】:

您可以这样做,而无需为数组分配指针:

typedef struct _MyData
{
    int Index;
    char Data[1];
} MyData;

后来,你这样分配:

int bcount = 256;
MyData *foo;

foo = (MyData *)malloc(sizeof(*foo) + bcount);

重新分配:

int newbcount = 512;
MyData *resized_foo;

resized_foo = realloc((void *)foo, sizeof(*foo) + newbcount);

【讨论】:

  • 在 C 中做 char Data[0]; 是不合法的
【解决方案6】:

从您所说的看来,您肯定必须将MyData 保留为静态数据块。在这种情况下,我认为对您开放的唯一选择是以某种方式(可选)以某种方式将这些数据结构链接在一起,以便在另一个过程中重新组装。

您需要MyData 中的其他成员,例如。

typedef struct _MyData
{
   int  Sequence;
   char Data[256];
   int  Index;
} MyData;

其中Sequence 标识重新组合数据的降序(序列号为零表示最终数据缓冲区)。

【讨论】:

  • 我无法理解您的概念。你能发布一些代码并解释一下总体思路吗?
  • 我是说您可以将这些数据缓冲区链接在一起以容纳所需的额外数据。例如。要传递大小为 600 字节的数据,您将调用您的函数(在单独的进程中)3 次: 序列 2:256 字节 序列 1:256 字节 序列 0:88 字节
【解决方案7】:

问题在于您提出问题的方式。不要考虑 C 语义:相反,要像黑客一样思考。解释准确您当前如何在正确的时间将数据输入其他进程,以及其他程序如何知道数据的开始和结束位置。其他程序是否需要一个以空字符结尾的字符串?如果你用 char[300] 声明你的结构,其他程序会崩溃吗?

你看,当你说“传递数据”给另一个程序时,你可能是在 [a] 欺骗另一个进程复制你放在它前面的内容,[b] 欺骗另一个程序让你覆盖它通常是“私人”内存,或 [c] 其他一些方法。不管是哪种情况,如果其他程序可以获取您更大的数据,那么一种方法可以将其提供给他们。

【讨论】:

  • 好的,想想代码注入。简单的。将数据放入结构中。分配内存,写入内存,在注入的应用中创建远程线程,运行线程。
  • [如果您仍在关注此线程...] 我们在同一页面上,我认为您正在使用 CreateRemoteThread()。但我想问的是:你如何让目标程序查看你的数据?您是否正在对他们的数据区域进行 memcpy 操作?您是否正在覆盖他们指向它的指针之一指向您的数据?
【解决方案8】:

我发现KIV 的技巧非常有用。不过,我建议先调查指针问题。

如果您查看 malloc 实现
(check this IBM article, Listing 5: Pseudo-code for the main allocator),
当您分配时,内存管理器会分配一个控制标头和
然后根据您请求的大小释放空间。
这很像说,

typedef struct _MyData
{
   int  size;
   char Data[1]; // we are going to break the array-bound up-to size length
} MyData;

现在,你的问题是,
您如何将这样的(尺寸错误的?)结构传递给其他进程?

这给我们带来了问题,
其他进程如何计算出这些数据的大小?
我希望 length 字段作为通信的一部分。

如果您拥有所有这些,那么将指针传递给另一个进程有什么问题?
其他进程是否会识别指向 a 的指针之间的区别? 结构和分配的内存?

【讨论】:

  • 感谢您的代码。问题是我们正在处理一个不再受支持的程序,所以我发现执行某些代码的唯一方法是通过简单的 DLL 注入。注入基本上是在对程序的主调用执行之后执行的,并且一旦在“旧版”软件中执行某个功能,它也会执行注册表清理。所以,除非你能给我一个正确的方法来将指针传递给注入的函数,否则我不能使用它们,因为它们会使程序崩溃
  • 我想我已经掌握了你想做的事情。麻烦的是,你似乎正在尝试一种“利用”的方法来实现你的目标。这将非常依赖于这个遗留程序的编写方式。我想不出任何具体的事情可以问你,这将帮助我在这里找出任何方案:-(
  • 如何使用类似于 FARPROC 的东西并传递指针的地址并以某种方式在注入的代码中获取它?
【解决方案9】:

您不能手动重新调整。

您可以做一些我在处理简单数据保存系统时所使用的技巧。 (非常简单的文件系统)。

typedef struct
{
    int index ;     
    char x[250];
} data_ztorage_250_char;

typedef struct
{
    int index;      
    char x[1000];
} data_ztorage_1000_char;

int main(void)
{
      char just_raw_data[sizeof(data_ztorage_1000_char)];
      data_ztorage_1000_char* big_struct;
      data_ztorage_250_char* small_struct;
      big_struct = (data_ztorage_1000_char*)big_struct; //now you have bigg struct
      // notice that upper line is same as writing 
      // big_struct = (data_ztorage_1000_char*)(&just_raw_data[0]);

      small_struct = (data_ztorage_250_char*)just_raw_data;//now you have small struct

      //both structs starts at same locations and they share same memory
     //addresing data is 
      small_struct -> index = 250;
}

【讨论】:

  • 正如我所说,我不能使用指针。我正在通过注入将该结构(可能不仅仅是一个 int 和一个在其中声明的 char)传递给另一个程序(该程序不再受支持,因此我们无法更改它,我正在使用注入在某些地方执行代码)。所以,我发送给那里的所有东西都必须用右侧声明。没有指针。
  • 在这种情况下你不能。在 struct 本身中没有写入 Data 的大小。结构仅定义数据和整数开头的位置,写入 Data[256],Data[257],Data[258],Data[259] 将覆盖索引。在这种情况下,例如仅使用链接器,您无法告诉程序您的整数现在基于数据处于不同的偏移量。
【解决方案10】:

您没有说明索引值的用途。

据我了解,您正在使用所示结构将数据传递给另一个程序。 您是否有理由不能将数据分解为 256 字节的块,然后相应地设置索引值?例如

数据为 512 字节,因此您发送一个结构,其中前 256 字节和索引 = 0,然后在数组中发送另一个结构,其后 256 字节和索引 = 1。

【讨论】:

  • 感谢 cmets。我将尝试再次解释这一点。我试图让一个不受支持的程序做一些它没有设计的事情。这样做的方法是注入一些代码,运行代码并完成它。有时我需要发送到该远程线程的数据更大,所以我需要将字符的大小设置为更大的大小。我不能分块发送信息,必须一次发送。
【解决方案11】:

一个非常非常简单的解决方案怎么样?你能做到吗:

typedef struct _MyData
{
   char Data[1024];
   int  Index;
} MyData;

我有一种感觉,我知道您的回答将是“不,因为我无法控制的其他程序需要 256 个字节”...如果这确实是您对我的回答的回答,那么我的回答将变为:这是不可能的。

【讨论】:

  • 不,我的回答是:如果明天我需要通过 2048 年会怎样?第二天100000000?
  • 使其成为可以想象到的最大尺寸;这将成为您代码的限制。
  • 哦,当然,添加错误检查,这样如果你需要传递的数据是一天 100000000,你就不会覆盖你不应该覆盖的内存。当那一天到来时,增加数据的大小。
  • 所以基本上我会分配大量内存并将大量内存注入另一个进程,即使我只需要发送几百 Ks。
  • 很遗憾,其他人的建议都被拒绝了——这是我能想到的最好的了!
猜你喜欢
  • 1970-01-01
  • 2011-07-20
  • 2013-07-29
  • 2019-08-22
  • 1970-01-01
  • 1970-01-01
  • 2010-10-12
  • 2010-09-29
  • 1970-01-01
相关资源
最近更新 更多