Tag: 语言律师

可以在其定义中采用具有自动存储持续时间的变量的地址吗?

是否允许在其定义的右侧获取对象的地址,如下面的foo()所示: typedef struct { char x[100]; } chars; chars make(void *p) { printf(“p = %p\n”, p); chars c; return c; } void foo(void) { chars b = make(&b); } 如果它被允许,它的使用是否有任何限制,例如,打印它可以,我可以将它与另一个指针等进行比较吗? 在实践中,它似乎在我测试的编译器上进行编译,大部分时间都是预期的行为(但并非总是如此 ),但这远非保证。

联合或结构是否允许从未初始化的实例进行分配?

这个问题是关于将未经宣传的自动变量分配给同一类型的另一个的定义或其他方面。 考虑 typedef struct { int s1; int s2; } Foo; typedef union { int u1; Foo u2; } Bar; int main() { { int a; int b = a; // (1) } { Foo a; Foo b = a; // (2) } { Bar a; a.u1 = 0; Bar b = a; // (3) […]

scanf是否保证不会在失败时更改值?

如果scanf系列函数无法与当前说明符匹配,是否允许写入存储成功值的存储? 在我的系统上,以下输出213两次但是有保证吗? 标准中的语言(C99或C11)似乎没有明确指出原始值应保持不变(无论它是否不确定)。 #include int main() { int d = 213; // matching failure sscanf(“foo”, “%d”, &d); printf(“%d\n”, d); // input failure sscanf(“”, “%d”, &d); printf(“%d\n”, d); }

到达函数结束而没有return语句

ANSI X3.159-1989,第3.6.6.4节,第33-35行: “如果执行了没有表达式的return语句,并且调用者使用了函数调用的值,则行为是未定义的。 到达终止函数的}等同于执行不带表达式的return语句。“ 对于类似的陈述,我一直在查看ISO/IEC 9899:1999(E) , ISO/IEC 9899:2011(E) , ISO/IEC 14882:2011(E)和ISO/IEC 14882:2014(E) ,特别是第二句话,但是我发现的所有内容都与函数main有关。 如果有人能指出我在这些文件中的任何一个文件中的正确位置(我不在乎哪个),我会很感激。

即使char已签名,’a’和’0’也始终具有正值?

根据环境和编译器设置,默认情况下char类型可以是有符号或无符号的,这意味着8位2s补码系统上单字符常量的值范围可以是-128..127或0..255 。 在无处不在的ASCII字符集中,其ISO-8859-X扩展或UTF-8编码,大写和小写字母以及数字的值低于127。 但是EBCDIC字符集不是这种情况: ‘A’是0xC1, ‘a’是0x81而’1’是0xF1。 由于这些值大于127,是否意味着char类型必须在8位EBCDIC系统上无符号? 或者’a’ , ‘A’和’1’有否定值? 其他字符集怎么样? 字母或数字可以有负值吗?

在int数组上使用memcmp严格符合吗?

以下程序是否是C中严格符合的程序? 我对c90和c99感兴趣,但c11的答案也是可以接受的。 #include #include struct S { int array[2]; }; int main () { struct S a = { { 1, 2 } }; struct S b; b = a; if (memcmp(b.array, a.array, sizeof(b.array)) == 0) { puts(“ok”); } return 0; } 在对不同问题的答案的评论中 ,Eric Postpischil坚持认为程序输出将根据平台而改变,主要是由于未初始化填充位的可能性。 我认为结构赋值会覆盖b所有位与b中的相同。 但是,C99似乎并没有提供这样的保证。 从第6.5.16.1节第2节: 在简单赋值 ( = )中,右操作数的值将转换为赋值表达式的类型,并替换存储在左操作数指定的对象中的值。 在复合类型的背景下,“转换”和“替换”是什么意思? 最后,考虑相同的程序,除了a和b的定义是全局的。 该计划是否是严格遵守的计划? […]

由于标准C委员会没有标准化gets()的简单替换,它应该是什么?

gets函数首先在C99中弃用,最后在C11中删除。 然而,在C库中没有直接替代它。 fgets()不是替代品,因为它不会删除最后的’\n’ ,这可能在文件末尾不存在。 许多程序员也错了。 有一个单行删除换行符: buf[strcspn(buf, “\n”)] = ‘\0’; ,但这是非常重要的,往往需要解释。 它也可能是低效的。 这会适得其反。 许多初学者仍然使用gets()因为他们的老师很蹩脚或他们的教程已经过时了。 微软提出了gets_s()和许多相关的函数,但是它并没有默默地截断超长行,这种约束违规的行为并不是很简单。 BSD和GNU libc都有getline ,在POSIX中标准化,通过realloc分配或重新分配缓冲区… 教初学者关于这个烂摊子的最佳方法是什么?

空值返回函数g可以返回f(); 当f返回void?

请考虑以下代码段: void f(void); void g(…) { … return f(); … } 这是return f(); 根据C11有效吗? 我并不主张使用这种模式:如果它起作用,它显然等同于f(); return; f(); return; ( return;如果它在函数g()的末尾,则本身将是多余的)。 我在C程序的静态分析的上下文中问这个问题,其中C代码已经由其他人编写,问题是根据标准判断它是否有效。 我认为C11 6.8.6.4:1意味着它是非标准的并且应该被静态拒绝。 是否有可能以不同的方式解释它(我在实际和其他高质量的源代码中找到了这种模式)? 约束 带有表达式的return语句不应出现在返回类型为void的函数中。 不带表达式的return语句只能出现在返回类型为void的函数中。

在`main`可选的结尾处使`return 0`的理由是什么?

从C99标准开始,如果在main的末尾没有提供return EXIT_SUCCESS ,则编译器需要生成等效的return 0或return EXIT_SUCCESS 。 在同一时间,对C ++语言标准也进行了相应且相同的更改。 我对两者的原因感兴趣,并且我猜测它们不太可能是完全独立且无关的变化。 我的问题是: 这种变化的记录理由是什么? 一个理想的答案将引用C和C ++的权威来源,这就是我用两种语言标记问题的原因。 请注意,与问题不同, 在ISO C ++中从main返回0的原因是什么? ,我不是在寻求关于是否在我的程序中写return 0建议 – 我在问为什么语言标准本身已经改变了。 为了帮助理解问题的目的,这里有更多的背景: 了解更改的原因有助于决定如何使用它。 理由通常包含在标准本身中。 例如,C90标准包括许多解释性脚注,例如脚注36,其开头是“此列表的意图……” 在我问到这个问题之前,我已经研究了自己寻找答案的标准,但没有找到答案。 我被要求帮助为一组程序员编写两种语言的编码标准,我想确保我理解为什么这个function存在,以便我可以准确地向其他人解释它的使用。

标准是否定义空指针常量以将所有位设置为零?

(我引用的是ISO / IEC 9899:201x) 在这里我们看到,整数常量表达式有一个整数类型: 6.6常量表达式 6. 整数常量表达式应具有整数类型,并且只能具有整数常量的操作数,枚举常量,字符常量,结果为整数常量的sizeof表达式,_Alignof表达式以及作为强制转换的直接操作数的浮点常量。 整数常量表达式中的转换运算符只能将算术类型转换为整数类型,除非作为sizeof或_Alignof运算符的操作数的一部分。 这适用于任何整数类型: 6.2.6.2整数类型 5.未指定任何填充位的值。符号位为零的有符号整数类型的有效(非陷阱)对象表示是相应无符号类型的有效对象表示,并且应表示相同的值。 对于任何整数类型,所有位为零的对象表示应该是该类型中零值的表示。 然后我们看到使用值为0的整数常量表达式定义空指针常量。 6.3.2.3指针 3. 值为0的整型常量表达式,或者类型为void *的表达式,称为空指针常量。 如果将空指针常量转换为指针类型,则保证将结果指针(称为空指针)与指向任何对象或函数的指针进行比较。 因此,空指针常量必须将其所有位设置为零。 但是在线和StackOverflow上有许多答案说这不是真的。 考虑到引用的部分,我很难相信他们。 (请使用最新标准的参考答案)