Python 在 C 中生成的字符串

Python Generated String in C

我需要在 C 中生成以下字符串:

$(python -c "print('\x90' * a + 'blablabla' + '\x90' * b + 'h\xef\xff\xbf')")

其中 a 和 b 是任意整数,blablabla 代表任意字符串。我试图通过首先创建

来做到这一点
char str1[size];

然后做:

for (int i = 0; i < a; i+=1) {

strcat(str1, "\x90");

}

接下来我再次使用strcat:

strcat(str1, "blablabla");

并且我再次 运行 循环,这次 b 次,以连接下一个 b x90 个字符。最后,我再次使用 strcat 如下:

strcat(str1, "h\xef\xff\xbf"); 

然而,这两个字符串不匹配。有没有一种更有效的方法可以在 C 中复制 python 的 * 的行为?还是我遗漏了什么?

对于单个 1 字节字符,您可以使用 memset 来部分复制 Python 的 *:

的行为
#include<stdio.h>
#include<string.h>

int main(void){
    char buffer[100];

    memset(buffer,'#',10);
    buffer[10] = '[=10=]';

    printf("%s\n",buffer);

    memset(buffer, '*', 5);
    buffer[5] = '[=10=]';

    printf("%s\n",buffer);

    return 0;
}

输出:

##########
*****

有关更强大的解决方案,请参阅 this

char str1[size];

即使假设您正确计算了大小,我也建议使用

char * str = malloc(size);

无论哪种方式,在以一种或另一种方式获得字符串所需的内存之后,您都必须先通过以下方式初始化它

str[0]=0;

如果您打算使用 strcat

for (int i = 0; i < a; i+=1) {
    strcat(str1, "\x90");
}

这很有用,如果 "\x90" 实际上是一个字符串(即由多个字符组成的东西)并且 该字符串是 short(很难给出一个硬边界,但大约 16 个字节是顶部) a 相当小 [1]。在这里,正如 John Coleman 已经建议的那样,memset 是更好的方法。

memset(str, '\x90', a);

因为您知道 "blablabla" 的存储位置,所以只需使用 strcpy 而不是 strcat

将其存储在那里
// strcat(str1, "blablabla");
strcpy(str + a, "blablabla");

但是,您需要 "blablabla" 之后字符的地址(无论哪种方式)。所以我什至不会那样做,而是这样:

const char * add_str = "blablabla";
size_t sl = strlen(add_str);
memcpy(str + a, add_str, sl);

然后,使用另一个 memset:

而不是第二个循环
memset(str + a + sl, '\x90', b);

最后但同样重要的是,再次 strcpy 代替 strcat 更好(这里,memcpy 没有帮助):

strcpy(str + a + sl + b, "h\xef\xff\xbf");

但是你需要它的大小来开始计算大小,所以最好还是像 blablabla 字符串那样做(记住尾部 '[=35=]')。

最后,我会将所有这些代码放入一个函数中,如下所示:

char * gen_string(int a, int b) {
    const char * add_str_1 = "blablabla";
    size_t sl_1 = strlen(add_str_1);
    const char * add_str_2 = "h\xef\xff\xbf";
    size_t sl_2 = strlen(add_str_2);

    size_t size = a + sl_1 + b + sl_2 + 1;
    // The + 1 is important for the '[=19=]' at the end

    char * str = malloc(size);
    if (!str) {
        return NULL;
    }
    memset(str, '\x90', a);
    memcpy(str + a, add_str_1, sl_1);
    memset(str + a + sl_1, '\x90', b);
    memcpy(str + a + sl_1 + b, add_str_2, sl_2);
    str[a + sl_1 + b + sl_2] = 0; // 0 is the same as '[=19=]'

    return str;
}

记得 free() 在某些时候重装 gen_string

如果 memsetmemcpy 调用列表变长,那么我建议这样做:

    char * ptr = str;
    memset(ptr, '\x90',    a   ); ptr += a;
    memcpy(ptr, add_str_1, sl_1); ptr += sl_1;
    memset(ptr, '\x90',    b   ); ptr += b;
    memcpy(ptr, add_str_2, sl_2); ptr += sl_2;
    *ptr = 0; // 0 is the same as '[=20=]'

甚至可以为 memsetmemcpy 创建一个宏:

#define MEMSET(c, l) do { memset(ptr, c, l); ptr += l; } while (0)
#define MEMCPY(s, l) do { memcpy(ptr, s, l); ptr += l; } while (0)

    char * ptr = str;
    MEMSET('\x90',    a   );
    MEMCPY(add_str_1, sl_1);
    MEMSET('\x90',    b   );
    MEMCPY(add_str_2, sl_2);
    *ptr = 0; // 0 is the same as '[=21=]'

#undef MEMSET
#undef MEMCPY

关于为什么按照我推荐的方式去做的理由,我建议你阅读博客 post Back to Basics(Stack Overflow 的创始人之一),它不仅是John Coleman 最喜欢的博客 post 也是我的。在那里你会了解到,在循环中使用 strcat 就像你第一次尝试的那样有二次 运行 时间,因此,为什么不按照你的方式使用它。

[1]如果a大and/or需要重复的字符串很长,更好的解决方案是这样的:

const char * str_a = "\x90";
size_t sl_a = strlen(str_a);

char * ptr = str;
for (size_t i = 0; i < a; ++i) {
    strcpy(ptr, str_a);
    ptr += sl_a;
}
// then go on at address str + a * sl_a