标签: c99

gcc - 2个版本,内联函数的不同处理

最近我在我的项目中遇到了一个问题.我通常在gcc-4中编译它,但在尝试在gcc-3中编译之后,我注意到了对内联函数的不同处理.为了说明这一点,我创建了一个简单的例子:

main.c中:

#include "header.h"
#include <stdio.h>

int main()
{
    printf("f() %i\n", f());
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

file.c:

#include "header.h"
int some_function()
{
    return f();
}
Run Code Online (Sandbox Code Playgroud)

header.h

inline int f()
{
    return 2;
}
Run Code Online (Sandbox Code Playgroud)

当我用gcc-3.4.6编译代码时:

gcc main.c file.c -std=c99 -O2
Run Code Online (Sandbox Code Playgroud)

我得到链接器错误(f的多个定义),如果我删除-O2标志,则相同.我知道,编译器没有内联任何东西,如果它不想要的,所以我认为它放在F中的目标文件中,而不是在这两个的情况下,内联它main.cfile.c,因此多个定义错误.显然,我可以通过制作f静态来解决这个问题,然后,在最坏的情况下,f在二进制文件中有一些.

但我尝试在gcc-4.3.5中使用以下代码编译此代码:

gcc main.c file.c -std=c99 -O2
Run Code Online (Sandbox Code Playgroud)

一切都运行正常,所以我假设f在两种情况下内联的新gcc 并没有f在二进制文件中有任何功能(在gdb中检查我是对的).

但是,当我删除-O2标志时,我得到两个未定义的引用int f().在这里,我真的不明白发生了什么.似乎gcc假设f会内联,所以它没有将它添加到目标文件中,但后来(因为没有-O2)它决定生成对这些函数的调用而不是内联,这就是链接器错误来自的地方.

现在问题是:我应该如何定义和声明我想要内联的简单和小函数,以便它们可以在整个项目中使用而不必担心各种编译器中的问题?并且让所有这些都成为静态的正确的事情吗?或者也许gcc-4被打破了,除非它们是静态的,否则我不应该在几个翻译单元中有多个内联函数的定义?

c compiler-construction gcc inline c99

3
推荐指数
1
解决办法
892
查看次数

是每个线程或每个进程的C99 fesetround()/ fegetround()状态?

我在网上找到的C和POSIX引用没有指定C99的fesetround()的线程安全性.甚至GNU文档也没有[1].状态是每线程还是每个进程?

[1] https://www.gnu.org/software/hello/manual/libc.html#Rounding

c floating-point c99 thread-safety c11

3
推荐指数
1
解决办法
401
查看次数

在没有UB的情况下将64位值截断为32位值

这个简单的代码片段是否具有C99标准的完全定义的行为?

{
  uint64_t longer = 0x122223333u;
  uint32_t shorter = longer;
  assert(shorter == 0x22223333u);
}
Run Code Online (Sandbox Code Playgroud)

如果没有,那么实现这一目标的标准兼容方法是什么(将一个uint64_t值的低32位放到uint32_t变量中)?

c c99

3
推荐指数
1
解决办法
2139
查看次数

GNU89,混合声明和循环初始声明

GCC和ICC的默认C语言是GNU89.GNU89允许混合声明,例如

int i;
i = 0;
int j;
Run Code Online (Sandbox Code Playgroud)

我推断(错误地)来自SO上的一些其他帖子,例如C:for loop int initial declaration,这意味着我可以做到

for(int i=0; i<n; i++)
Run Code Online (Sandbox Code Playgroud)

使用GNU89但是当我这样做时,我得到了

error: 'for' loop initial declarations are only allowed in C99 mode
Run Code Online (Sandbox Code Playgroud)

显然,混合声明和循环初始声明不是一回事(即一个并不暗示另一个).

如果我只能有一个,我宁愿有循环初始声明.当然,我可以使用GNU99,但这不是重点.默认值是GNU89,它已经破坏了一些C89规则(它还允许BCPL/C++样式注释).是否存在允许混合声明而不是循环初始声明的一些基本原因?

c gcc c99 c89

3
推荐指数
1
解决办法
409
查看次数

clang和gcc与复合文字的不同行为

最近遇到了复合文字,据我所知,以下是使用它的正确方法.幸运的是,它适用于ubuntu上的gcc和clang.

int main() {
  int *p = (int []) {1, 2};
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是,我注意到使用复合文字的另一种方法,如下所示.感觉有点奇怪; 这只是数组初始化器.下面的代码用clang编译好,但是用gcc编译失败了array initialized from non-constant array expression.

int main() {
  int p[] = (int []) {1, 2};
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是故意还是什么?

ENV:

  • gcc(Ubuntu 4.8.2-19ubuntu1)4.8.2
  • Ubuntu clang版本3.5-1ubuntu1(主干)(基于LLVM 3.5)

CMD:

  • gcc test.c
  • clang test.c

c gcc c99 clang compound-literals

3
推荐指数
1
解决办法
532
查看次数

-O0处的内联函数导致clang中的链接失败

我正在尝试使用各种优化级别的clang编译以下代码:

#include <stdio.h>

inline int foo() { return 42; }

int main() {
    printf("%d\n", foo());
}
Run Code Online (Sandbox Code Playgroud)

-O1,-O2,-O3,和-Os,它编译成功,但使用时失败-O0:

$ clang -O0 -o main main.c
Undefined symbols for architecture x86_64:
  "_foo", referenced from:
      _main in main-8b9319.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Run Code Online (Sandbox Code Playgroud)

Clang的内联兼容性-O0可以解释(和变通方法)的失败,但是无论优化级别如何,我都天真地期望这会失败.似乎一些优化已经启用了一些东西来阻止这种链接错误的发生,但我很好奇它们是什么样的优化,以及为什么它们似乎具有不同于单独使用的语义.-O1inline-O0

c optimization inline c99 clang

3
推荐指数
1
解决办法
796
查看次数

C99删除stricmp()和strnicmp()?

在功能stricmp()strnicmp()在C99去除?当我尝试针对C99编译时,我总是得到警告隐式声明函数stricmp()(以及strnicmp()).例如,下面的简单代码让我发出警告.

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

char arr[100]="hello";
char arr2[100]="hEllo";

int main()
{
   int n=-1;
   printf("%d\n",n);
   n=strnicmp(arr,arr2,3);   // the same when use the function stricmp();
   printf("%d\n",n);

   getchar();
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我尝试针对C99(gcc -Wall -std=c99 main.c -o main)编译这段代码时,我收到了警告.但是当我没有编译它时-std=c99,不会抛出任何警告.但是,即使存在隐式声明的警告,我的代码仍然正常.

这是为什么?那是一个错误吗?如果不是一个错误,那么C99的变化究竟发生了什么?

c string c99

3
推荐指数
2
解决办法
5653
查看次数

可变长度阵列和灵活阵列成员之间有什么区别?

我已经在ISO C99委员会草案中看到,结构可能有一个不完整的数组,其末端具有未指定的大小,称为Flexible Array Member.

另一方面,C99还具有可变长度数组,它允许在编译时声明大小不恒定的数组.

我认为FAM是一种特殊的VLA,但我看到有两个SO用户声称不是.此外,阅读维基百科部分sizeof,它表示这sizeof两者的行为不同.

为什么它们都存在而不只是一个?(他们的用例太不一样了吗?)

此外,哪些其他相关行为对于每个行为都不同?

c c99 variable-length-array flexible-array-member

3
推荐指数
1
解决办法
637
查看次数

如何制作接受不同类型的功能?

我有这个冒泡排序功能:

void bubble_sort(float* array, int length)
{
    int c, d;
    float temp;

    for (c = 0; c < (length - 1); c++) {
        for (d = 0; d < length - c - 1; d++) {
            if (array[d] > array[d + 1]) {
                temp = array[d];
                array[d] = array[d + 1];
                array[d + 1] = temp;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如何更改它以便我也可以使用它double?我希望能够一次传递一个float数组,另一次传递一个double数组,但它必须是相同的函数.像这样的东西:

float farr[SIZE];
double darr[SIZE];
...
bouble_sort(farr, SIZE);
bouble_sort(darr, SIZE);
Run Code Online (Sandbox Code Playgroud)

编辑:我重写了排序功能,它现在似乎工作正常.你怎么看?

void bubble_sort(void* generalArray, int lenght_row, char type) …
Run Code Online (Sandbox Code Playgroud)

c sorting algorithm c99

3
推荐指数
1
解决办法
164
查看次数

如何抑制PC-Lint Note 970 for int main(void)函数?

我有一个带有ANSI C代码的Visual Studio Windows控制台应用程序.在函数的定义是这样的:

int main(void)
{
    // do stuff
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是,PC-Lint报告int类型的以下消息

注释970:在typedef之外使用修饰符或类型 [MISRA 2012 Directive 4.6,advisory]

我需要保留main函数和Note 970的int类型.因此,我想仅针对主函数定义来抑制Note 970.我不想在源代码上添加// lint!e970.

我想知道是否可以仅使用PC-Lint选项定义主函数来抑制此消息.

c c99 misra pc-lint ansi-c

3
推荐指数
1
解决办法
418
查看次数