C99 6.3.2.3/3 值为 0 的整型常量表达式,或此类转换为 void * 类型的表达式,称为空指针常量。55) 如果将空指针常量转换为指针类型,则生成的指针,称为空指针,保证与任何对象或函数的指针比较不相等。
它是否说两个空指针比较不相等?但他们确实:
int *a = 0;
int *b = 0;
assert(a == b); // true
Run Code Online (Sandbox Code Playgroud)
我想知道在这种情况下有什么不平等?
我在 EEPROM (4KB) 中有很多配置数据,我以打包结构读取这些数据。在我的固件中,我需要非常频繁地读取/更改这些值,并且打包结构的性能不是最佳的,所以我有第二个结构,它完全相同,只是没有打包。我必须将每个值从打包结构中一一复制到解压结构中,这很容易出错,因为当我向打包结构中添加一个值时,我还必须记住将其添加到复制函数中。
有没有更聪明的方法来做到这一点?
我试图isatty()在我的 C 代码中使用 posix 函数来判断输出是否被重定向。然而,要做到这一点,我需要一个文件描述符,从我的研究来看,它似乎fileno()不再包含在stdio.h. 是否有其他获取文件描述符的方法?
直到今天,我总是在互联网上读到 gcc 是最好的 C 编译器(至少对于学生编程水平而言,紧随其后的是 Clang)。然而,在“ 21st Century C ”中,Ben Klemens 先生建议 c99 比运行更好(?)gcc -std=c99(实际行是 [第 11 页]:其他人很久以前就切换到 C99 作为默认值......)
我无法找到有关 c99 编译器主题的任何内容,所以我的问题是:
这些命令之间有什么区别吗?如果有的话,哪一个更好?
编辑:该段落中明确提到了标准 C99,但是从一开始建议的编译方法是命令:
gcc erf.c -o erf -lm -g -Wall -O3 -std=gnu11
Run Code Online (Sandbox Code Playgroud)
然而,作者在第 11 页指出:
POSIX 标准指定 c99 存在于您的系统上,因此上述行的与编译器无关的版本将是:
c99 erf.c -o erf -lm -g -Wall -O3
Run Code Online (Sandbox Code Playgroud)
这似乎表明这两个命令存在差异。我无法找到任何其他信息,也无法从文本中清楚地看出第二行到底是什么(我的 Cygwin 上也没有 c99 的手册页)。
由于不值得一提的原因,我想知道布尔表达式是否有标准定义值。例如
int foo () {
return (bar > 5);
}
Run Code Online (Sandbox Code Playgroud)
背景是我担心我们的团队将 TRUE 定义为与 1 不同的东西,并且我担心有人可能会这样做:
if (foo() == TRUE) { /* do stuff */ }
Run Code Online (Sandbox Code Playgroud)
我知道最好的选择就是简单地做
if (foo())
Run Code Online (Sandbox Code Playgroud)
但你永远不知道。
布尔表达式是否有定义的标准值或者由编译器决定?如果有的话,标准值是否包含在C99中?C89呢?
GCC 和 Clang 都允许指定的初始化器引用正在初始化的结构或数组的成员,但是这是合法且定义良好的行为吗?
以下代码示例针对 GCC 和 Clang 进行编译和运行,并{ .a = 3, .b = 6, }在两种情况下输出:
#include <stdio.h>
typedef struct
{
int a;
int b;
} foo;
int main()
{
foo bar = {
.a = 3,
.b = bar.a + 3,
};
printf("{ .a = %d, .b = %d, }\n", bar.a, bar.b);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
GCC 为指定的初始化生成以下输出(编译器资源管理器链接),这表明该示例的操作是安全的:
mov dword ptr [rbp - 4], 0
mov dword ptr [rbp - 16], 3
mov eax, dword ptr …Run Code Online (Sandbox Code Playgroud) 如果我们有具有灵活成员数组的结构,例如:-
struct test{
int n;
int b[];
};
Run Code Online (Sandbox Code Playgroud)
然后,即使在 malloc 完成之前,如果我们尝试打印:-
struct test t;
printf("%lu",sizeof(t.b[0]);
Run Code Online (Sandbox Code Playgroud)
这属于未定义行为吗?
C99 是这样描述灵活成员数组的:-
“如果这个数组没有元素,它的行为就好像它有一个元素一样,但如果尝试访问该元素或生成一个超过该元素的指针,则该行为是未定义的。”
因此,访问b[0]是未定义的行为,但它是否也适用于 sizeof 运算符,因为它是编译时运算符并且t.b[0]在运行时永远不会在这里访问?
当我在 gcc 编译器中尝试这个时,我输出了 4 个字节,但如果它属于未定义的行为,那么我们不能认为这个输出是理所当然的,除非 gcc 给出了一些扩展,在这种情况下我不确定。
我发现了几个讨论有符号与无符号编译器优化的问题。一般结论是,由于溢出的未定义行为,有符号允许更多优化。但是,我没有找到任何关于签名如何与操作重新排序一起发挥作用的讨论。
考虑表达式
a - b + c
Run Code Online (Sandbox Code Playgroud)
如果所有值都是无符号的,编译器总是可以重新排序操作(添加a和c首先可以提高性能)。
如果所有值都有符号,编译器必须证明重新排序不会导致发生溢出。一般来说a + c,编译器可能会溢出,因此它可以重新排序的内容受到限制。
我是否正确地认为编译器可以更自由地对无符号值的操作进行重新排序?
编辑
我本来想问有关*and等其他操作,但我想这个问题只对and/有意义。一般来说,无论整数是有符号还是无符号,乘法和除法都不能重新排序。+-
我目前有一个结构
typedef struct Entry {
int counter;
void *block;
} Entry;
Run Code Online (Sandbox Code Playgroud)
和一个mmap的内存块
void *memPtr = mmap(NULL, someSize*1024, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
Run Code Online (Sandbox Code Playgroud)
然后我将条目一直添加到第一部分(这是愚蠢的,但那部分有点无关紧要),如下:
int AddEntry(void *data) {
Entry entry;
entry.counter = 1;
entry.block = malloc(sizeof(char *) * SECTOR_SIZE);
memcpy(entry.block, data, SECTOR_SIZE);
memcpy(&memPtr[0], &entry, sizeof(Entry));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这里的问题Entry是只有16个字节长,因为block是a void pointer.什么是保证该块最好的办法实际上的sizeof的大小(字符*)*SECTOR_SIZE和实际上有数据足够的空间,以及如何将一个加载data到entry.block?
谢谢!
我从一个网站上读到C99解除了限制,即C中的变量必须在块的顶部声明.我在下面的程序中测试过,确实如此,因为我没有错误.但是在同一个程序中如果我在for循环的第一个语句中声明一个变量,我得到错误:
'for' loop initial declarations are only allowed in C99 mode|
这里有两件事.确实允许在程序中间声明变量,正如我所做的那样i,为什么我不允许在for循环语句中执行此操作?第二,如果我的编译器(Codeblocks/gcc)已经不在C99模式,为什么我在中间而不是顶部声明变量时没有出错?
#include <stdio.h>
int main (void)
{
//Proof that initialization in middle works (for i)
printf("Enter\n");
char string[20];
scanf("%s", string);
int i=20;
printf("%s,%i", string, i);
//Proved that it works
for(int j=0; j<10; j++) //THIS IS NOT ALLOWED
printf("%d\n", j);
}
Run Code Online (Sandbox Code Playgroud)