【问题标题】:Force C99 Compliant Compilation in clang在 clang 中强制 C99 兼容编译
【发布时间】:2017-09-18 14:59:41
【问题描述】:

我正在尝试编写一些需要compile on solaris in c99 mode 的C99 代码,但我无法访问solaris 机器。相反,我尝试在 OSX 上使用clang 执行此操作。但是,使用(文件 min.c):

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

int main() {
  printf("%d\n", (int) strnlen("hello world", 5));
  return 0;
}

我没有收到关于 strnlen 的任何错误或警告

$ clang -std=c99 -pedantic-errors -Wall -Wextra min.c
$ ./a.out
5

即使strnlen is a 2008 posix extension.

这与:

Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

有什么方法可以让clang 严格符合 c99,以便我有更好的机会在 solaris 上进行移植?

【问题讨论】:

  • 符合并不意味着你不能使用任何你想要的功能。你在库中有它,你在 h 文件中有原型,所以编译和链接没有任何警告是 100% 的。
  • 有道理,我想我需要在与 (solaris) 存在兼容性问题的机器上建立同一个库。
  • @PeterJ_01-- strnlen() 不是标准库的一部分,尽管strnlen_s() 在附件 K 中。标准说 "a strictly conforming program shall use only those features of the language and library specified in this International Standard."
  • @David Bowling 这是本文档中的废话之一。它实际上不允许使用任何(甚至是您为特定项目编写的)库。您可以自己编写具有任何名称的任何函数。如果您在程序中写strnlen(),您认为编译器应该产生错误或警告?当然不是。
  • @PeterJ_01:严格来说,不存在符合标准的编译器或符合标准的库。编译器和库是可以构成一致实现的两个组件。这两个组件不仅必须正确,还必须正确协同工作。

标签: c clang


【解决方案1】:

可能有一个不合格的实现,很可能是由于头文件问题,或者您的编译器和头文件不匹配。

在我的系统上(Ubuntu 17.04、x86_64、clang 4.0.0)我得到:

$ clang -std=c99 -pedantic-errors -Wall -Wextra min.c
min.c:5:24: warning: implicit declaration of function 'strnlen' is invalid in C99 [-Wimplicit-function-declaration]
  printf("%d\n", (int) strnlen("hello world", 5));
                       ^
1 warning generated.
$ 

但是strnlen,虽然它不是由 C 标准定义的,但它是一个保留标识符。当包含&lt;string.h&gt; 时,所有以strwcsmem 开头后跟小写字母的标识符都将被保留。

C99 7.1.3p2 说:

如果程序在上下文中声明或定义标识符 它是保留的(除了 7.1.4 允许的),或定义一个保留的 标识符作为宏名称,行为未定义。

更新:正如MM的评论正确指出的那样,您的程序没有声明或定义strnlen;它只是指它。我将不得不考虑其中的含义。

由于您的程序具有未定义的行为(可能),因此诊断它不需要符合要求的实现。对于您的编译器来说,向您发出警告肯定会更加用户友好,但它不这样做并不意味着它不符合要求。

如果您使用的是未保留的标识符,则需要编译器对其进行诊断。例如,stpcpy 函数也是一个 POSIX 扩展,但它的名称没有保留。如果这个程序编译没有警告或错误-std=c99 -pedantic-errors

#include <stdio.h>
#include <string.h>
int main(void) {
    char s[10];
    stpcpy(s, "hello");
    puts(s);
}

那么你就有理由抱怨了。

【讨论】:

  • 感谢基思,问题似乎是我在 OSX 上的标准库属于“厨房水槽”种类,我没有一个很好的方法来排除 POSIX.1 扩展用clang编译时。就我而言,strnlen 实际上在 ...
  • 该程序没有声明或定义strnlen。在 C99 中调用未声明的函数是违反约束的;它没有像 C89 那样隐式声明函数。 (我也不相信在 C89 模式下,由于声明了保留标识符,这个隐式声明会导致 UB)。
  • @M.M:非常正确。我已经相应地更新了我的答案,我将不得不再考虑一下。
  • 我倾向于说实现是不合格的,因为未能发出使用未声明函数的诊断;但是我认为将标准解释为允许实现在保留空间中声明其他标识符是有一些优点的。
  • 另外,fwiw,我稍微澄清了这个问题(即我需要生成符合 c99 的代码以便以后在 solaris 上编译,但我的 osx lib 包括 posix.1 扩展,可能还有更多不是那里是犹太洁食)。
【解决方案2】:

基于@DietrichEpp's answer,以下似乎可行:

clang -std=c99 -Wpedantic -Wall -Wextra -D_POSIX_C_SOURCE=200112L min.c
min.c:5:24: warning: implicit declaration of function 'strnlen' is invalid in C99
      [-Wimplicit-function-declaration]
  printf("%d\n", (int) strnlen("hello world", 5));
                       ^
  1 warning generated.

standards man page appears to support this:

POSIX.1-2001 与 C99 保持一致,因此在 C99 中标准化的所有库函数也在 POSIX.1-2001 中标准化。

这会在带有 Xcode 和 clang 的 OSX 10.12.6 上产生预期的结果。

【讨论】:

    猜你喜欢
    • 2014-04-12
    • 2016-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-12
    • 2023-04-09
    • 1970-01-01
    相关资源
    最近更新 更多