gcc 使用带有clang的c11标准来使用strcpy_s

prdp8dxp  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(366)

我正在运行OS X Sierra,并试图编译一个使用strcpy_s的c程序,但我安装的clang编译器使用的是c99标准,而from what I've read strcpy_s需要c11。
这是我要编译的代码

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

int main(void)
{
    char source[] = "Test string";
    char destination[50];
    if(strcpy_s(destination, sizeof(destination), source))
        printf("string copied - %s",destination);

    return 0;
}

这是我用来编译的命令

$ clang copytest.c -o copytest
copytest.c:11:5: warning: implicit declaration of function 'strcpy_s' is invalid in C99 [-Wimplicit-function-declaration]
        if(strcpy_s(copied_string, sizeof(copied_string), source))
           ^
1 warning generated.
Undefined symbols for architecture x86_64:
  "_strcpy_s", referenced from:
      _main in copytest-e1e05a.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

我试过用标准标志编译...
clang -std=c11 copytest.c -o copytest
但是我得到了同样的“invalidinc99”警告。我也尝试过用gcc编译,但是仍然得到同样的c99警告。
我尝试通过自制软件升级,显示如下
警告:gcc 9.2.0已安装并且是最新的
我有clang版本9.0.0

$ clang -v
Apple LLVM version 9.0.0 (clang-900.0.39.2)

我的xcode版本是Xcode 9.2,从我所读到的一切来看,它应该带有c11支持。
我在编译时做错了什么吗?我的代码本身不正确吗?This是我在这里找到的唯一一个类似的问题,但它甚至没有答案。谢谢

qkf9rpyu

qkf9rpyu1#

_s函数是2011 C标准的一个 * 可选 * 组件(附件K),而据本人所知,它们从未被实现为任何C库的一个集成部分。2可移植代码不能依赖于它们的可用性。(Microsoft的Windows版C编译器实现了一组重叠的函数,这些函数具有相同的名称但语义不同(并且至少存在一个bolt-on implementationSee this old answer, and the much longer question and answer it links to, for more detail。)
此外,_s函数没有解决它们本来要解决的问题(不安全的字符串处理);有必要对每次使用strcpy进行适当的修复,而不是像附录K的作者所希望的那样,全局搜索strcpy并将其替换为strcpy_s等。如果您确实对适当的修复进行了适当的思考,那么您将不需要任何_s函数来实现它。例如,下面是示例程序修复版本:

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

int main(void)
{
    char source[] = "Test string";
    char destination[50];

    size_t srclen = strlen(source);
    if (srclen + 1 > sizeof destination) {
        fprintf(stderr, "string too long to copy - %zu bytes, need %zu\n",
                sizeof destination, srclen + 1);
        return 1;
    } else {
        memcpy(destination, source, srclen + 1);
        printf("string copied - %s\n", destination);
        return 0;
    }
}

这里有一个更好的版本:

#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    if (argc != 2) {
        fprintf(stderr, "usage: ./test 'message of arbitrary length'\n");
        return 1;
    }
    char *destination = strdup(argv[1]);
    if (!destination) {
        perror("strdup");
        return 1;
    }
    printf("string copied - '%s'\n", destination);
    free(destination);
    return 0;
}

因此:永远不要使用任何_s函数。如果你需要编写一个在Windows上编译而没有警告的程序,把#define _CRT_SECURE_NO_WARNINGS 1放在每个文件的顶部,这样MSVC就不会给你不好的建议。

7kqas0il

7kqas0il2#

如果所有的程序员,甚至大多数程序员一直都在写上面建议的解决方案,那么这些函数就不需要了。我们有很多证据表明,许多程序员没有写这样仔细的代码,可以追溯到Spaf在20世纪80年代末对Robert T Morris手指蠕虫的注解。
您也不希望为strcpy的每个调用点重复10行代码。这会导致代码不可读。更重要的是,zwol建议的实际上只是他声称我们不需要的函数的一个实现。一个好的程序员会接受它,把它放在一个头中,并给它起一个有用的名字,也许是checked_strcpy?或者甚至是strcpy_s?
第二个建议的实现,据说更好,但不是--它会在我们已经有缓冲区的时候导致分配。分配是昂贵的,在任何地方使用这种方法都会对perf不利。它还引入了新的复杂性,因为现在我们必须释放每个重复的字符串--想象一下重复调用strcat来做这件事。
这里有一个非常好的跨平台实现:https://github.com/intel/safestringlib
我也不确定这是否真的有什么不同,但值得一看-https://github.com/coruus/safeclib

相关问题