string.endswith 方法转换为 C

Conversion of string.endswith method into C

我正在开始一个个人项目,将用 python 编写的解释器转换为 C。这纯粹是为了学习目的。

我遇到的第一件事是尝试转换以下内容:

if __name__ == "__main__":
    if not argv[-1].endswith('.py'):
        ...

到目前为止,我已经为 endswith 方法

完成了以下转换
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

bool endswith(char* str, char* substr)
{
    // case1: one of the strings is empty
    if (!str || !substr) return false;

    char* start_of_substring = strstr(str, substr);

    // case2: not in substring
    if (!start_of_substring) return false;

    size_t length_of_string    = strlen(str);
    size_t length_of_substring = strlen(substr);
    size_t index_of_match      = start_of_substring - str;

    // case2: check if at end
    return (length_of_string == length_of_substring + index_of_match);

}

int main(int argc, char* argv[])
{
    char *last_arg = argv[argc-1];
    if (endswith(last_arg, ".py")) {
        // ...
    } 

}

这看起来是否涵盖了 endswith 中的所有情况,还是我遗漏了一些边缘情况?如果是这样,如何改进?最后,这不是批评,而是编写 C 应用程序时的一个真正问题:编写 C 需要比在 python 中做同样的事情多 5-10 倍的代码是否常见(或者更多是因为我我是初学者,不知道如何正确地做事?)

及相关:https://codereview.stackexchange.com/questions/54722/determine-if-one-string-occurs-at-the-end-of-another/54724

Does this look like it's covering all the cases in an endswith, or am I missing some edge cases?

你至少遗漏了子字符串出现两次或更多次的情况,其中一次出现在最后。

我不会为此使用 strstr()。相反,我会根据两个字符串的相对长度来确定要在主字符串中查找的位置,然后使用 strcmp()。示例:

bool endswith(char* str, char* substr) {
    if (!str || !substr) return false;

    size_t length_of_string    = strlen(str);
    size_t length_of_substring = strlen(substr);

    if (length_of_substring > length_of_string) return false;

    return (strcmp(str + length_of_string - length_of_substring, substr) == 0);
}

关于那个return语句:str + length_of_string - length_of_substring等同于&str[length_of_string - length_of_substring]——也就是说,指向相同长度的尾随子串的第一个字符的指针作为 substrstrcmp 函数比较两个 C 字符串,返回小于、等于或大于零的整数,具体取决于第一个参数按字典顺序是小于、等于还是大于第二个。特别是,strcmp() returns 0 当它的参数相等时,这个函数 returns 正是这样一个测试的结果。

is it common that writing C will require 5-10x more code than doing the same thing in python

Python 是一种比 C 更高级的语言,因此 C 代码的任务通常比 Python 相同任务的代码更长。此外,C 块被显式分隔使 C 代码比 Python 代码稍长。不过,我不确定 5-10 倍是否是一个好的估计,而且我认为在这种情况下你是在比较苹果和橙子。类似于您的 Python 代码的代码就是

int main(int argc, char* argv[]) {
    if (endswith(argv[argc-1], ".py")) {
        // ...
    } 
}

C 没有内置 endswith() 函数是另外一回事。

对于初学者来说,函数应该这样声明

bool endswith(const char* str, const char* substr);

因为传递给函数的字符串都没有在函数内更改。

其次是这个if语句

if (!str || !substr) return false;

您检查是否至少有一个指针是空指针的地方对于字符串函数来说是多余的。

所有标准字符串函数都遵循共同约定,即如果用户传递空指针,则函数行为未定义。也就是说,函数的用户有责任传递非空指针。

第三,如果strstr

的调用
char* start_of_substring = strstr(str, substr);

将return一个非空指针它并不意味着第一个字符串以第二个字符串结尾或不以第二个子字符串结尾。例如,第一个字符串可以包含第二个字符串的多个副本。在这种情况下,您的函数将 return false.

函数如下面的演示程序所示。

特别是假定任何字符串都以空字符串结尾。

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

bool endswith( const char *s1, const char *s2 )
{
    size_t n1 = strlen( s1 );
    size_t n2 = strlen( s2 );
    
    return ( n2 == 0 ) || ( !( n1 < n2 ) && memcmp( s1 + n1 - n2, s2, n2 ) == 0 );
}

int main(void) 
{
    const char *s1 = "Hello World!";
    const char *s2 = "World!";
    
    printf( "\"%s\" ends with \"%s\" is %s.\n", 
            s1, s2, endswith( s1, s2 ) ? "true" : "false" );
            
    return 0;
}

程序输出为

"Hello World!" ends with "World!" is true.

Finally, this isn't a criticism but more a genuine question in writing a C application: is it common that writing C will require 5-10x more code than doing the same thing in python

听起来有点多,但这取决于你做什么。是的,通常 C 代码更长。部分是因为语言本身,部分是因为它有一个巨大的库,用于各种你必须在 C 中从头开始实现的东西。你看到函数 argv[-1].endswith('.py') 了吗?好吧,有人为此编写了代码。你只是看不到而已。

但是有些特性有时可以使 C 中的代码更短。例如,在 Python 中,赋值是语句。在 C 中,它们是表达式。这意味着在 C 中,您可以执行以下操作:

if(c = foo()) { // Assign c to the return value of foo 
                // and then evaluate it as a Boolean

您也可以使用逗号运算符,如下所示:

if((c == foo(), ++c) > 4) {

通常,这样的构造不是一个好主意。特别是如果它们很复杂。但至少它是 C 代码有时可以更短的示例。