一个简单的问题:enum { a } e = 1;有效吗?
换句话说:分配一个不存在于枚举常量值集中的值是否会导致定义明确的行为?
演示:
$ gcc t0.c -std=c11 -pedantic -Wall -Wextra -c
<nothing>
$ clang t0.c -std=c11 -pedantic -Wall -Wextra -c
<nothing>
$ icc t0.c -std=c11 -pedantic -Wall -Wextra -c
t0.c(1): warning #188: enumerated type mixed with another type
# note: the same warning for enum { a } e = 0;
$ cl t0.c /std:c11 /Za /c
<nothing>
Run Code Online (Sandbox Code Playgroud) 示例代码:
#define X(x,y) x y
#define STR_(x) #x
#define STR(x) STR_(x)
STR(X(Y,Y))
Run Code Online (Sandbox Code Playgroud)
调用:
$ gcc t222.c -std=c11 -pedantic -Wall -Wextra -E -P
"Y Y"
$ gcc t222.c -std=c11 -pedantic -Wall -Wextra -E -P -D"Y()"
"YY"
Run Code Online (Sandbox Code Playgroud)
为什么 GCC 会删除预处理标记之间的空格?
例如, clang 不会:
$ clang t222.c -std=c11 -pedantic -Wall -Wextra -E -P -D"Y()"
"Y Y"
Run Code Online (Sandbox Code Playgroud)
UPD1。,不知何故,gcc 考虑了和之间的空格Y:
$ gcc t222.c -std=c11 -pedantic -Wall -Wextra -E -P -D"Y()" -D"Z=STR(X(Y,Y))"
"YY"
$ gcc t222.c -std=c11 -pedantic -Wall -Wextra -E -P …Run Code Online (Sandbox Code Playgroud) https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html:
\n\n\n一些用户尝试使用它
\n-Wpedantic来检查程序是否严格符合 ISO C。他们很快发现它并没有达到他们想要的效果:它找到了一些非 ISO 实践,但不是所有\xe2\x80\x94,只有那些 ISO C需要诊断的实践,以及其他一些已添加诊断的实践。
有哪些未发现的非 ISO 实践示例-pedantic?
众所周知,对于任何浮点类型的变量,x != xiff(当且仅当)x是NaN(非数字)。或相反的版本:x == xiffx不是NaN。那么,如果使用语言的自然能力可以获得相同的结果,那么WG14为什么决定定义isnan(x)( math.h) 呢?动机是什么?更好的代码可读性?
额外问题:isnan(x)和之间是否有任何功能差异x != x?
如果sizeof(int) == sizeof(long),则INT_MIN == LONG_MIN && INT_MAX == LONG_MAX始终为真?
有没有真实存在的案例证明“不真实”?
UPD。类似的问题:是否有 CHAR_BIT > 8 的托管 C 实现?。
#include <stdio.h>
#include <stdint.h>
#include <fenv.h>
#include <math.h>
int main()
{
typedef union { uint32_t u; float f; } ufloat;
ufloat val;
float arg = 2401.999999;
int r;
r = fesetround(FE_DOWNWARD);
val.f = sqrtf(arg);
printf ("FE_DOWNWARD %22.13a [0x%x] %d\n", val.f, val.u, r);
r = fesetround(FE_TONEAREST);
val.f = sqrtf(arg);
printf ("FE_TONEAREST %22.13a [0x%x] %d\n", val.f, val.u, r);
r = fesetround(FE_TOWARDZERO);
val.f = sqrtf(arg);
printf ("FE_TOWARDZERO %22.13a [0x%x] %d\n", val.f, val.u, r);
r = fesetround(FE_UPWARD);
val.f = sqrtf(arg);
printf ("FE_UPWARD %22.13a [0x%x] …Run Code Online (Sandbox Code Playgroud) 示例代码(t928.c):
#include <stdio.h>
#include <fenv.h>
#if _MSC_VER && ! __clang__
#pragma fenv_access (on)
#else
#pragma STDC FENV_ACCESS ON
#endif
int main(void)
{
int i = fesetround( FE_UPWARD );
if ( ! i )
{
printf( "%.1f\n", 0.0 );
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
调用:
$ clang t928.c -Wall -Wextra -std=c11 -ffp-model=strict -pedantic && ./a.exe
0.1
$ cl t928.c /std:c11 /Za /fp:strict && ./t928.exe
0.1
Run Code Online (Sandbox Code Playgroud)
版本:
$ clang --version
clang version 12.0.0
$ cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29913 for …Run Code Online (Sandbox Code Playgroud) 要执行相同的转换并保持 ANSI 兼容性,您可以在将函数指针转换
uintptr_t为数据指针之前将其转换为 a:Run Code Online (Sandbox Code Playgroud)int ( * pfunc ) (); int *pdata; pdata = ( int * ) (uintptr_t) pfunc;
C 的基本原理,修订版 5.10,2003 年 4 月:
即使使用显式强制转换,将函数指针转换为对象指针或 void 指针也是无效的,反之亦然。
C11:
7.20.1.4 能够保存对象指针的整数类型
是否意味着pdata = ( int * ) (uintptr_t) pfunc;无效?
正如史蒂夫·萨米特所说:
C 标准的编写假设指向不同对象类型的指针,尤其是指向函数而不是对象类型的指针,可能具有不同的表示形式。
虽然pdata = ( int * ) pfunc;会导致UB,但似乎会pdata = ( int * ) (uintptr_t) pfunc;导致IB。这是因为“任何指针类型都可以转换为整数类型”和“整数可以转换为任何指针类型”并且uintptr_t …
C2x,7.21.9.2 fseek 函数:
概要
Run Code Online (Sandbox Code Playgroud)#include <stdio.h> int fseek(FILE *stream, long int offset, int whence);
为什么fseek有long int offset而不是long long int offset?
似乎在具有数据模型LLP64 或 ILP32 的操作系统(例如 Microsoft Windows)上2147483647(2 GB)可能不够。
1990 年,PJ Plauger 写道(强调是后加的):
然而,标准 C 为您提供了额外的安全级别。据我所知,这是其他语言标准中没有提供的水平。它承诺,如果您避免使用某些名称集,您将不会遇到冲突。因此,标准 C 使得编写高度可移植的应用程序变得更加容易。
在 C11 中,关键字_Alignas(例如)是alignas与<stdalign.h>. 这里我们看到关键字是_Alignas, not alignas(因为在 C11 之前的版本中alignas没有保留)。因此,不会与可能的用户定义发生冲突alignas。
然而,在 C2x 中, thealignas是一个关键字并且<stdalign.h>不提供任何内容(并且 C2x 没有提及__alignas_is_defined宏——缺陷?)。这意味着在 C2x 中,任何包含用户定义的 C2x 之前的代码都alignas将导致语义违规,从而破坏向后兼容性。
问题:
alignas(例如)成为关键字而不是宏的理由是什么?