C标准是否要求n个元素数组的大小是元素大小的n倍,可以通过显式语句还是通过严格的逻辑推理来满足其要求?
例如,可能int (*x)[5] = malloc(5 * sizeof **x);无法为五个数组请求足够的空间int?
C 2011 [N1570] 6.5.3.4 7显示了计算数组中元素数量的示例sizeof array / sizeof array[0].但是,例子不是标准的规范部分(根据前言第8段).
6.2.5 20表示数组类型描述了具有特定类型的连续分配的非空对象集,但对所需的总内存没有提及.
这只是一个语言律师问题; 实际的实现是无关紧要的.(为了安抚那些想要具体示例的人,假设一个C实现需要对大型数组进行额外的内存管理,因此创建一个数组需要创建一些额外的数据来帮助管理内存.)
使用了什么形式的内存地址空间?
今天,大型扁平虚拟地址空间很常见.从历史上看,已经使用了更复杂的地址空间,例如一对基地址和偏移量,一对段号和一个偏移量,一个字地址加上一个字节或其他子对象的索引,依此类推.
不时,各种答案和评论声称C/C++指针本质上是整数.这是一个不正确的C/C++模型,因为各种地址空间无疑是一些关于指针操作的C规则的原因.例如,不在数组之外定义指针算法简化了对基本和偏移模型中指针的支持.指针转换的限制简化了对地址加额外数据模型的支持.
这种反复出现的断言激发了这个问题.我正在寻找有关各种地址空间的信息,以说明C/C++指针不一定是一个简单的整数,并且考虑到要支持的各种机器,C/C++对指针操作的限制是明智的.
有用的信息可能包括:
这是一个广泛的问题,所以我愿意接受有关管理它的建议.我很高兴看到一个通用包容性答案的协作编辑.然而,这可能无法授予应得的声誉.我建议投票多个有用的贡献.
在块范围内考虑此代码:
struct foo { unsigned char a; unsigned char b; } x, y;
x.a = 0;
y = x;
Run Code Online (Sandbox Code Playgroud)
C [N1570] 6.3.2.1 2说"如果左值指定了一个自动存储持续时间的对象,该对象可以用寄存器存储类声明(从未使用过它的地址),并且该对象未初始化(未使用初始化程序声明)在使用之前没有对它进行任何分配),行为是不确定的."
虽然已为某个成员x分配了一个值,但x尚未执行任何分配,并且尚未对其进行分配.因此,看起来6.3.2.1 2告诉我们xin 的行为y = x是未定义的.
但是,如果我们为每个成员分配了一个值x,那么x为了6.3.2.1 2的目的考虑未初始化似乎是不合理的.
(1)严格来说,标准中是否有任何内容导致6.3.2.1 2不适用于(未定义)上述代码?
(2)假设我们正在修改标准或确定对6.3.2.1的合理修改2,是否有理由偏好以下其中一项而不是其他?(a)6.3.2.1 2不适用于结构.(b)如果一个结构的至少一个成员被赋予了一个值,则该结构在6.3.2.1的目的下不是未初始化的.(c)如果一个结构的所有已命名的1个成员都被赋予了一个值,那么该结构是为6.3.2.1的目的而未初始化2.
1结构可能具有未命名的成员,因此并不总是可以为结构的每个成员分配值.(即使结构初始化,未命名的成员也具有不确定的值,每6.7.9 9.)
C 2018 5.1.2.3 6说:
符合实施的最低要求是:
根据抽象机器的规则严格评估对易失性对象的访问.
在程序终止时,写入文件的所有数据应与根据抽象语义执行程序的结果相同.
交互设备的输入和输出动态应按照7.21.3的规定进行.这些要求的目的是尽快出现无缓冲或行缓冲输出,以确保在程序等待输入之前实际出现提示消息.
这是该程序的可观察行为.
从表面上看,这不包括程序的退出状态.
关于exit(status),7.22.4.4 5说:
最后,控制权返回给主机环境.如果值
status为零或EXIT_SUCCESS,则返回状态成功终止的实现定义形式.如果值status是EXIT_FAILURE,地位的实现定义的形式成功终止返回.否则返回的状态是实现定义的.
标准没有告诉我们这是可观察行为的一部分.当然,这种exit行为纯粹是C的抽象机器的描述是没有意义的; 除非在环境中可观察到,否则向环境返回值没有意义.所以我的问题不在于退出状态是否可观察到这是否是C标准对可观察行为的定义中的缺陷.或者标准中的其他地方是否有适用的文字?
C 2018 6.7.6.1 1 说:
\n\n\n如果在声明 \xe2\x80\x9c T D1 \xe2\x80\x9d 中,D1具有以下形式
\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 * 类型限定符列表opt D
\n并且在声明 \xe2\x80\x9c T D \xe2\x80\x9d 中为ident指定的类型为\n\xe2\x80\x9c派生声明符类型列表T \xe2\x80\x9d,则指定的类型对于ident \nis \xe2\x80\x9c派生声明符类型列表类型限定符列表指向T \xe2\x80\x9d 的指针。\n对于列表中的每个类型限定符,ident是一个 so-qualified 指针。
\n
这个问题是关于最后一句话的,但是让\xe2\x80\x99s先解决第一句话。
\n考虑一下声明int * const * foo。这里T是int,D1是* const * foo,类型限定符列表是const,D是* foo。
那么TD …
根据我的理解,如果你有一个std::vector<int>和一个std::vector<float>,编译器会创建两个类,每个类一个.因此,虽然减少了写入的代码量,但是不会减少可执行文件的大小(如果我错了,请纠正我).
即使类型是指针,是否也是如此?例如,是否会实例化std::vector<SomeClass*>并且std::vector<SomeOtherClass*>必然会导致编译器为两个实例中的每一个生成单独的代码?
如何将用户数输入从11,5转换为11.5?
我尝试了以下作为回调:
before_validation :comma_to_delimiter
def comma_to_delimiter
self.price.to_s.gsub(',', '.').to_f
end
Run Code Online (Sandbox Code Playgroud)
但这不起作用.我希望用户能够输入他想要的任何分隔符 - 当前,当用户使用逗号而不是点时,应用程序会抛出错误.
也许我不正确理解C++或者它是编译器的错误?
uint8_t a = 0x00;
uint8_t b = 0xFF;
if( a - b == 1 )
{
doNothing();
}
Run Code Online (Sandbox Code Playgroud)
doNothing未被调用(如预期的那样),因为(ab)的结果在比较操作中被隐式地转换为第二个操作数的类型.对于数字,它是签名int.好的.
if( a - b == (uint8_t)1 )
{
doNothing();
}
Run Code Online (Sandbox Code Playgroud)
doNothing STILL没有被调用,但现在我不明白它的原因!我已经明确地将数字转换为uint8!
if( (uint8_t)(a - b) == 1 )
{
doNothing();
}
Run Code Online (Sandbox Code Playgroud)
现在doNothing终于被召唤了,但为什么呢?如何减去两个uint8返回一个int?
编译器是用于ARM Cortex M3的uVision ARMCC.
我有一个非常简单的代码,其中逻辑移位以奇怪的方式使用~0值
据我所知,它与签名/无符号数据类型有关
#include <stdio.h>
void printfbits(int x) {
for (int i=7; i>=0;i--) {
printf("%d", x>>i & 1);
}
printf("\n");
}
int main() {
printfbits(~0>>1);
}
Run Code Online (Sandbox Code Playgroud)
我期待0111111,而不是1111111.我也试过,没有成功
printfbits(((unsigned int)~0)>>1);
Run Code Online (Sandbox Code Playgroud) 可以int (*)[]是不完整的类型吗?
C 2018 6.2.5 1 说:
在翻译单元内的各个点,对象类型可能不完整(缺乏足够的信息来确定该类型对象的大小)或完整(具有足够的信息)。
因此,似乎如果类型的大小已知,则该类型是完整的。6.2.6.1 28 规定某些类型的指针必须具有相同的大小(指向void和字符的指针、指向兼容类型的指针、指向结构的指针和指向联合的指针),但指向其他类型的指针可能会有所不同。
在 C 实现中,所有指针或指向数组的所有指针int都具有相同的大小,则 的大小int (*)[]是已知的,因此它是完整的。在一个实现中,比如说,对大数组使用不同的指针,大小是未知的,所以它是不完整的。
正如MM 指出的那样,根据 6.7.2.1 3 中的约束,结构不得包含类型不完整的成员,最终的灵活数组成员除外。这表明具有相同大小的指针struct { int (*p)[]; }的实现必须接受,而具有不同大小的实现必须接受此类数组的大小必须诊断约束违规。(这反过来意味着这样的声明不是严格遵守 C 的一部分。)