它看起来像它可能是,有(至少在C99),可以适用于长度修改int
:%hhd
,%hd
,%ld
和%lld
指signed char
,short
,long
和long long
.甚至还有一个长度修饰符适用于double
:%Lf
均值long double
.
问题是他们为什么省略float
?按照模式,它可能是%hf
.
我有以下代码在g ++下编译,但不是用clang编译.
如果以各种次要方式进行更改,Clang将编译代码,例如合并2个名称空间声明.
// The problem disappears without namespaces.
namespace Root {
// The problem disappears if 'g' is in the global namespace, and we change
// the friend declaration to '::g'
// The problem disappears if 'g' has void return type.
// The problem disappears if we get rid of the 'Value' template argument
// and the 'value' parameter.
template<typename Value, typename Defaulted = void>
bool g(Value value);
// The problem disappears if MyClass is not a template.
template<typename …
Run Code Online (Sandbox Code Playgroud) 根据文档,struct tm *gmtime(const time_t *timer);
应该将time_t
指向转换timer
为分解时间.
现在有没有理由为什么他们决定让函数取指针time_t
而不是time_t
直接传递?
据我所知,它time_t
是算术类型,因此应该可以直接传递(我也觉得它适合于a long
).此外,似乎有任何特定的NULL
指针处理(这可能有动机传递指针).
有什么我想念的吗?今天还有什么相关的东西?
JLS v7 第18章中的语法似乎与文档中其他地方的结构不同,但对我来说似乎存在差异.特别是在第15章中,规则是:
RelationalExpression:
ShiftExpression
RelationalExpression < ShiftExpression
RelationalExpression > ShiftExpression
RelationalExpression <= ShiftExpression
RelationalExpression >= ShiftExpression
RelationalExpression instanceof ReferenceType
Run Code Online (Sandbox Code Playgroud)
这使得foo instanceof Bar
一个RelationalExpression(因此也就是一个EqualityExpresson)可以在EqualityExpression规则中用作LHS,该规则产生foo instanceof Bar == false
一个EqualityExpression.
但是在查看第18章中的语法时,他们对它进行了简化:
Expression2:
Expression3 [Expression2Rest]
Expression2Rest:
{ InfixOp Expression3 }
instanceof Type
Run Code Online (Sandbox Code Playgroud)
这看起来很奇怪,这意味着我们可以将Expression3
二进制运算符链接在一起,或者我们可以检查一个类型Expression3
.具体现在foo instanceof Bar
是一个Expression2
,但我没有看到使用Expression2
平等比较的LHS 是有效的.
我是否错过了第18章的语法中的某些内容foo instanceof Bar == false
?请注意,根据第15章中的规则并根据我的编译器,它是一个有效的表达式.
以rc = scanf("%f", &flt);
输入为例42ex
.scanf
读取的实现会42e
认为它会在之后遇到一个数字或符号,并在读取时首先意识到x
它没有得到它.如果它在这一点上推回都x
和e
?或者它应该只推回x
.
我想问的原因是将GNU的libc中的后续调用gets
返回ex
表明他们已经推后两x
和e
,但标准说:
除非规范包含n个指定符,否则从流中读取输入项.输入项目被定义为输入字符的最长序列,其不超过任何指定的字段宽度,并且是匹配输入序列的前缀或后缀[245]输入项目之后的第一个字符(如果有)仍然未读.如果输入项的长度为零,则指令的执行失败; 除非文件结束,编码错误或读取错误阻止了流的输入,否则此条件是匹配失败,在这种情况下,它是输入失败.
我将其解释为因为42e
匹配输入序列的前缀(因为例如42e1
将是匹配的输入序列),这应该意味着它将被42e
视为应该被读取的输入项而仅留下x
未读.如果流仅支持单个字符回退,那么实现起来也会更方便.
stdio中的一些函数似乎将流作为最后一个参数,例如:
char *fgets(char *restrict, int, FILE *restrict);
int fputs(const char *restrict, FILE *restrict);
size_t fread(void *restrict, size_t, size_t, FILE *restrict);
size_t fwrite(const void *restrict, size_t, size_t, FILE *restrict);
Run Code Online (Sandbox Code Playgroud)
有些人将它作为第一个论点:
int fgetpos(FILE *restrict, fpos_t *restrict);
int fseek(FILE *, long, int);
Run Code Online (Sandbox Code Playgroud)
为什么这种不一致?这些功能是在标准库演变的不同时间添加的吗?在那种情况下,这是第一次,为什么公约改变了?
我意识到,由于省略号(并且类似于首先和最后),fprintf
与朋友一起或多或少地需要FILE*
第一个(或至少早期fclose
).
假设我有一个结构并将偏移量提取给成员:
struct A {
int x;
};
size_t xoff = offsetof(A, x);
Run Code Online (Sandbox Code Playgroud)
如果指针以struct A
标准符合方式提取成员,我该怎么办?当然假设我们有struct A*
正确的偏移量.一种尝试是做类似的事情:
int getint(struct A* base, size_t off) {
return *(int*)((char*)base + off);
}
Run Code Online (Sandbox Code Playgroud)
这可能会工作,但要注意的例子指针算术只有似乎标准中定义,如果指针是相同的阵列(或一个过去的结束)的指针,这不一定是这种情况.从技术上讲,构造似乎依赖于未定义的行为.
另一种方法是
int getint(struct A* base, size_t off) {
return *(int*)((uintptr_t)base + off);
}
Run Code Online (Sandbox Code Playgroud)
这也可能会起作用,但请注意,intptr_t
不需要存在,据我所知,算术intptr_t
不需要产生正确的结果(例如我记得有些CPU有能力处理非字节对齐的地址,这会建议在数组中intptr_t
每个步骤增加8 char
.
看起来标准中有遗忘的东西(或者我错过的东西).
这是我的测试代码:
#include <cstdio>
struct A {
int a;
int b;
int c __attribute__((aligned(4096)));
int d;
}t;
int main()
{
printf("%d\n",sizeof(t));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
结果是8192,但我无法弄清楚原因.
根据GNU C库,它允许分配stdio
就好像它们是普通变量(我知道这是一个扩展).我试过以下程序:
#include <stdio.h>
int main()
{
stdout = NULL;
printf("Crash and %s\n", "burn");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在运行程序时,它将按预期进行段错误,但是当我gdb
以值运行时stdout
仍然不是NULL
:
_IO_vfprintf_internal (s=0x0, format=0x400631 "Crash and %s\n", ap=0x7fffffffe210) at vfprintf.c:1297
1297 vfprintf.c: No such file or directory.
(gdb) print stdout
$1 = (struct _IO_FILE *) 0x7ffff7dd77a0
(gdb)
Run Code Online (Sandbox Code Playgroud)
为什么不gdb
报告正确的值stdout
?
进一步调查我发现它似乎存储stdout
在地址0x600940
,寻找struct _IO_FILE*
那里我找到一个与gdb
报告相同的指针stdio
:
(gdb) print stdout
$1 = (struct _IO_FILE *) 0x7ffff7dd77a0
(gdb) print …
Run Code Online (Sandbox Code Playgroud) 还有的警告的理由在这里,但没有回答的全貌.例如,以下代码触发警告:
(int)round(M_PI);
Run Code Online (Sandbox Code Playgroud)
但另一方面,以下代码不会:
double d;
(int)(d = round(M_PI));
Run Code Online (Sandbox Code Playgroud)
这不是:
(int)M_PI;
Run Code Online (Sandbox Code Playgroud)
的理由是,你不应该转换简单地铸造为int,但你应该使用round
,floor
或类似的功能.但是,使用round
仍然会触发警告,但如上所示,类型化常量或指定的变量则不会.
所以,如果它是坏的,从投double
来int
,那么当你写为什么不报警触发(int)d
或(int)M_PI
?如果你想转换返回值,应该以什么方式规避警告?是否有警告可以更正确/合理的方式处理这些危险的转换?