最近我在我的项目中遇到了一个问题.我通常在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.c和file.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和POSIX引用没有指定C99的fesetround()的线程安全性.甚至GNU文档也没有[1].状态是每线程还是每个进程?
[1] https://www.gnu.org/software/hello/manual/libc.html#Rounding
这个简单的代码片段是否具有C99标准的完全定义的行为?
{
uint64_t longer = 0x122223333u;
uint32_t shorter = longer;
assert(shorter == 0x22223333u);
}
Run Code Online (Sandbox Code Playgroud)
如果没有,那么实现这一目标的标准兼容方法是什么(将一个uint64_t值的低32位放到uint32_t变量中)?
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++样式注释).是否存在允许混合声明而不是循环初始声明的一些基本原因?
最近遇到了复合文字,据我所知,以下是使用它的正确方法.幸运的是,它适用于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:
CMD:
我正在尝试使用各种优化级别的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
在功能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的变化究竟发生了什么?
我已经在ISO C99委员会草案中看到,结构可能有一个不完整的数组,其末端具有未指定的大小,称为Flexible Array Member.
另一方面,C99还具有可变长度数组,它允许在编译时声明大小不恒定的数组.
我认为FAM是一种特殊的VLA,但我看到有两个SO用户声称不是.此外,阅读维基百科部分sizeof,它表示这sizeof两者的行为不同.
为什么它们都存在而不只是一个?(他们的用例太不一样了吗?)
此外,哪些其他相关行为对于每个行为都不同?
我有这个冒泡排序功能:
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) 我有一个带有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选项定义主函数来抑制此消息.