在标准C(C99/C11)中,我们有所谓的整数常量表达式,它们是常量表达式,其操作数都是常量整数.
以下定义适用:
标准C99,第6.6节(第6节):
整数常量表达式)应具有整数类型,并且只能具有整数常量,操作数,枚举常量,字符常量,结果为整数常量的sizeof表达式,以及作为强制转换的直接操作数的浮点常量.
这在更一般的常量表达式的定义之后出现.
(由于在常量表达式之后定义了整型常量表达式,我假设前者是最后一个的特殊情况.)
另一方面,条件表达式被视为常量表达式,受以下规则约束:
标准C99,第6.6节:
常量表达式不应包含赋值,递增,递减,函数调用或逗号运算符,除非它们包含在未评估的子表达式中.
通过展开条件表达式的含义,我们可以归结为后缀表达式和/或一元表达式.
现在,如果我们将这些约束应用于整数常量表达式,我们粗略地得到它们由条件表达式组成,这些条件表达式的限制使得每个操作数都是整数/枚举/字符常量(或浮动常量紧跟在强制转换之前),并且没有赋值,递增,递减,函数调用或逗号运算符.
sizeof
运算符,也没有未计算的操作数. 我的问题是:E中
是否间接禁止以下操作员:
&
(地址),*
(间接),[]
(数组下标),.
(结构成员),->
(指向struct成员的指针).另外,复合文字是否也被禁止?
备注:我有兴趣回答严格符合程序的问题(C99/C11).
我认为它们不能处于E的任何子表达式中,但我不确定这是否完全正确.我的快速推理如下:
T
. &
出现在E中的F之前,则&F输入一个操作数,其类型为"指向T的指针",这在E中是不允许的(尽管F不是一个对象,但只是一个整数值,所以不能应用).因此不能出现在任何E中 …人们总是说宏是不安全的,而且它们不是(直接)对其参数进行类型检查,等等.更糟糕的是:当发生错误时,编译器会给出内在和难以理解的诊断,因为宏只是一团糟.
是否有可能以与函数几乎相同的方式使用宏,通过安全的类型检查,避免典型的陷阱以及编译器提供正确诊断的方式.
让我们快速记住宏生成的一些典型陷阱.
例1
#define SQUARE(X) X*X
int i = SQUARE(1+5);
Run Code Online (Sandbox Code Playgroud)
预期值i
:36.真值i
:11(宏观扩展:) 1+5*1+5
.陷阱!
(典型)解决方案(例2)
#define SQUARE(X) (X)*(X)
int i = (int) SQUARE(3.9);
Run Code Online (Sandbox Code Playgroud)
预期价值i
:15.真实价值i
:11(宏观扩张后:(int) (3.9)*(3.9))
.陷阱!
(典型)解决方案(例3)
#define SQUARE(X) ((X)*(X))
Run Code Online (Sandbox Code Playgroud)
它适用于整数和浮点数,但它很容易被破坏:
int x = 2;
int i = SQUARE(++x);
Run Code Online (Sandbox Code Playgroud)
预期值i
:9(因为(2+1)*(2+1)
...).真值i
:12(宏扩展:((++x)*(++x))
,给出3*4
).陷阱!
在这里可以找到一种很好的宏检查方法:
但是我想要更多:某种界面或"标准"语法,以及(少量)易于记忆的规则.意图是"能够使用(不实现)宏"与尽可能类似的功能.这意味着:写得好的假函数.
为什么在某种程度上有趣?
我认为这是在C中实现的一个有趣的挑战. …
在标准C(我的意思是C99或C11)中,我们有所谓的整数常量表达式,它们是常量表达式,其操作数都是常量整数.还有其他约束,以避免表达式中的逗号运算符.
但是,在某些特殊情况下,允许使用其他非整数对象(甚至是非常量对象).
例如,如果将sizeof
运算符应用于大小在转换时间中已知的对象,则允许将其作为整数常量表达式的一部分(请注意,sizeof
始终返回整数值).
此外,有时也允许显式转换为整数类型.
标准C99建立以下规则:
标准C99,第6.6节(第6节):
整数常量表达式)应具有整数类型,并且只能具有整数常量,操作数,枚举常量,字符常量,结果为整数常量的sizeof表达式,以及作为强制转换的直接操作数的浮点常量.
我的问题是: "浮动常数是演员的直接操作数"的确切含义是什么?
浮点常数类似于3.14e + 3,或者是0x2.11p-5.
也就是说,不是float类型的一般常量表达式,而只是浮点文字.
然后,我明白在上面的定义中只允许这样的事情:
(int) 3.14
Run Code Online (Sandbox Code Playgroud)
但是不允许涉及浮动文字的操作.
这排除了以下情况:
(int) -3.14 /* The minus sign is not part of the constant: it is an operator */
(int) (3.14) /* The parenthesis are an operator acting on the literal 3.14 */
Run Code Online (Sandbox Code Playgroud)
最后一种情况不需要在转换时间中执行任何浮点算术运算,并且相当于没有括号:(int) 3.14
.
但是,它不是演员的直接操作数.
那么,我们是否必须考虑那(int) (3.14)
是[有效整数常量表达式的一部分] (根据定义)?
另一方面,编译器GCC(带选项:-std …
我想做一些看似不可能的事情.
我想写3个文件:main.c,foo.h,foo.c.
我们的想法是在foo.h或foo.c中定义一个结构,使其成员在main.c中可见.其中一个struct成员具有FILE
标准头中定义的类型<stdio.h>
.但是<stdio.h>
必须在main.c文件中保持不可见的函数和宏.
该解决方案必须符合标准C(C99和/或C11)和便携式.那可能吗?
标题foo.h在main.c和foo.c中都是#included .
标准头文件<stdio.h>
仅在foo.c中包含#included ,但在main.c中不包含.
我想声明struct
如下:
struct myfile_s {
FILE *F;
char *filename;
char buff[100];
} myfile;
Run Code Online (Sandbox Code Playgroud)
对于以下内容,只有成员FILE *F
才是重要的.
结构myfile
将由foo.c中出现的函数初始化和修改.
目的是myfile
通过foo.h中extern
声明的函数对文件进行操作,而foo.h中的函数又必须在foo.c中定义.
文件操作涉及标准函数<stdio.h>
,但这些函数必须隐藏在main.c文件中.但是,我想直接从main.c访问到成员 …
新标准C(ISO/IEC 9899:2023,又名C23),
在附录H中,定义了几个宏和类型,
相对于实数和复数算术,
并符合 ISO/IEC 60559 标准(浮点算术)。
根据 H.1 小节,存在三个
实现定义的宏来测试
与附件 H 定义的一致性。
__STDC_IEC_60559_TYPES__
__STDC_IEC_60559_BFP__
__STDC_IEC_60559_DFP__
Run Code Online (Sandbox Code Playgroud)
此外,要“激活”关联的宏和类型,
用户必须定义宏:
__STDC_WANT_IEC_60559_TYPES_EXT__
Run Code Online (Sandbox Code Playgroud)
该标准的措辞在几个细节上很明确:
__STDC_IEC_60559_BFP__
是由编译器定义的,则意味着_FloatN
,_FloatN_t
和其他_FloatN*
类型也已定义。__STDC_IEC_60559_DFP__
是由编译器定义的,则意味着_DecimalN
,_DecimalN_t
和其他_DecimalN*
类型也已定义。__STDC_IEC_60559_TYPES__
无论哪种情况,都会定义宏。__STDC_IEC_60559_TYPES__
一个宏__STDC_IEC_60559_BFP__
或(或两者)。__STDC_IEC_60559_DFP__
在 H.11 小节中,类型long_double_t
被添加到 中<math.h>
。
long_double_t
但是,我无法推断在哪些条件下可以确保给定实现中的存在。
问题:
如果__STDC_IEC_60559_TYPES__
已定义,是否足以确定long_double_t
也在 中定义<math.h>
?
我的怀疑来自以下可能出现的特殊情况:
__STDC_IEC_60559_TYPES__
和__STDC_IEC_60559_DFP__
已定义,但__STDC_IEC_60559_BFP__
未定义。在本例中,定义了十进制类型。
但是,long_double_t
不是十进制类型。
子问题:
宏是否 …
我在标准 C++的工作草案中发现了一个可能的矛盾。我首先陈述事实,我的问题在最后。
当整数转换等级建立时,[conv.rank]/1.1表示
任何两个有符号整数类型 [...] 不应具有相同的整数转换等级,即使它们具有相同的表示。
Type
wchar_t
是一种独特的类型,它具有实现定义的有符号或无符号整数类型作为其基础类型。
最后,[conv.rank]/1.8:
的行列
char8_t
,char16_t
,char32_t
,和wchar_t
应等于其基础类型的行列([basic.fundamental])。
如果它wchar_t
被实现为有符号整数类型,它将与它的底层类型具有相同的等级,它是一些其他整数类型的不同类型。
因此,我们有两个具有相同等级的不同有符号整数类型,与 [conv.rank]/1.1 相矛盾。
这是一个实际的矛盾,还是我误解了 C++ 中两个可简单复制的类型是不同的类型?
根据Microsoft提供的定义,FXPT2DOT30类型出现在为BMP文件定义结构CIEXYZ时:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd371828(v=vs.85).aspx
但是,我无法在任何地方找到FXPT2DOT30的确切定义.它的确切定义是什么?应该保留什么样的数据?
我在这个网站上已经阅读了几个关于这个主题的问题,但我仍然有疑问.
在标准C中,我们可以阅读:
6.3.2.3.p.5:整数可以转换为任何指针类型.[...]
6.3.2.3.p.6:任何指针类型都可以转换为整数类型.[...].
省略的文本(将放在括号[...]中)只讨论转换失败时可能发生的问题.
但是我的问题更为笼统:
我的问题是:我的解释(3)是正确的吗?
另一方面,当我们定义一个大小为N的类型T的数组时,
由于我们可以对数组的位置进行整数运算,
因此很明显,至少在"本地"级别,在数组中,
我们有相应的数组内存块的
运算方式与从0到N-1的数字集相同.
通过定义数组或分配的对象,我们可以确定,在C中,
内存地址可以被"本地"视为算术上等同于整数的子集.
然而,这种"局部"行为不足以得出
标准C假设存储器模型的结论,该存储器模型的存储器地址可被视为"仅一个且同一组整数"的一部分.
然而,6.3.2.3.p5/p6似乎"暗示"这个更强大的断言,尽管我并不完全确定.
另一个问题可能会带来更多亮点:
p
,q
,(即:p != q
)中,当转换成整数型,所得到的整数值变得相等.