Questions tagged «language-lawyer»

有关编程语言和环境的正式或权威规范的复杂性的问题。


6
允许编译器优化掉局部volatile变量吗?
是否允许编译器对此进行优化(根据C ++ 17标准): int fn() { volatile int x = 0; return x; } 对此吗? int fn() { return 0; } 如果是,为什么?如果没有,为什么不呢? 关于此主题的一些思考:当前的编译器将其编译fn()为放置在堆栈中的局部变量,然后将其返回。例如,在x86-64上,gcc创建以下代码: mov DWORD PTR [rsp-0x4],0x0 // this is x mov eax,DWORD PTR [rsp-0x4] // eax is the return register ret 现在,据我所知,标准并没有说应该将局部volatile变量放入堆栈中。因此,此版本同样不错: mov edx,0x0 // this is x mov …

1
为什么019不是JavaScript语法错误?还是为什么019> 020
如果我输入019 > 020JavaScript控制台(在Chrome和Firefox中都经过测试),则会得到答案true。 这是由于020被解释为OctalIntegerLiteral(等于16),而019显然是被解释为DecimalLiteral(等于19)。如19大于16,019 > 020则为true。 让我感到困惑的是为什么019将其解释为DecimalLiteral第一位。这是什么产品?DecimalIntegerLiteral不允许019: DecimalIntegerLiteral :: 0 NonZeroDigit DecimalDigits_opt OctalIntegerLiteral也不允许019(因为9不是八进制数字): OctalIntegerLiteral :: 0 OctalDigit OctalIntegerLiteral OctalDigit OctalDigit :: one of 0 1 2 3 4 5 6 7 因此,从我在规范中看到的内容来看,019实际上应该拒绝它,我不明白为什么将其解释为十进制整数。 我猜这里有某种兼容规则,但是我没有找到正式的定义。可以请任何人帮助我吗? (为什么需要这样做:我正在使用JavaCC开发Java的JavaScript / ECMAScript解析器,因此必须特别注意其规范-及其偏差。)



13
通过下标获取一个最后一个数组元素的地址:是否符合C ++标准?
我已经看到它多次断言C ++标准不允许以下代码: int array[5]; int *array_begin = &array[0]; int *array_end = &array[5]; 是&array[5]合法的C ++代码,在这种情况下? 如果可能的话,我想参考标准的答案。 知道它是否符合C标准也很有趣。如果不是标准的C ++,为什么要决定将其与array + 5or区别对待&array[4] + 1?

10
空隙的大小是多少?
这句话会产生什么? void *p = malloc(sizeof(void)); 编辑:问题的扩展。 如果sizeof(void)在GCC编译器中产生1,则分配1字节的内存,指针p指向该字节,p ++是否会递增为0x2346?假设p为0x2345。我说的是p,而不是* p。

3
为什么有时不需要在lambda中捕获const变量?
考虑以下示例: #include <cstdlib> int main() { const int m = 42; [] { m; }(); // OK const int n = std::rand(); [] { n; }(); // error: 'n' is not captured } 为什么我需要n在第二个Lambda中捕获而不是m在第一个Lambda中捕获?我检查了C ++ 14标准中的5.1.2节(Lambda表达式),但找不到原因。您能指出我对此段的解释吗? 更新:我在GCC 6.3.1和7(主干)中都观察到了此行为。在这两种情况下(variable 'm' cannot be implicitly captured in a lambda with no capture-default specified),Clang …



10
为什么对于不能TriviallyCopyable的对象,std :: memcpy的行为将无法定义?
来自http://en.cppreference.com/w/cpp/string/byte/memcpy: 如果对象不是TriviallyCopyable(例如标量,数组,C兼容结构),则该行为是不确定的。 在我的工作中,std::memcpy很长时间以来,我们一直使用以下方法按位交换不可TriviallyCopyable的对象: void swapMemory(Entity* ePtr1, Entity* ePtr2) { static const int size = sizeof(Entity); char swapBuffer[size]; memcpy(swapBuffer, ePtr1, size); memcpy(ePtr1, ePtr2, size); memcpy(ePtr2, swapBuffer, size); } 从来没有任何问题。 我了解滥用std::memcpy非TriviallyCopyable对象并导致下游未定义行为是微不足道的。但是,我的问题是: std::memcpy与非TriviallyCopyable对象一起使用时,为什么自身的行为不确定?为什么标准认为有必要指定该标准? 更新 针对此帖子和该帖子的答案已修改了http://en.cppreference.com/w/cpp/string/byte/memcpy的内容。当前的描述是: 如果对象不是TriviallyCopyable(例如标量,数组,与C兼容的结构),则除非程序不依赖于目标对象的析构函数的影响(不是由memcpy)运行,否则行为是不确定的。目标对象(以结束,但不是以开头memcpy)是通过其他一些方式(例如,新放置)来启动的。 聚苯乙烯 @Cubbi的评论: @RSahu如果可以保证UB下游,它将使整个程序未定义。但我同意,在这种情况下似乎有可能绕过UB,并相应地修改了cppreference。

3
陷阱表示
C语言中的“陷阱表示”是什么(某些示例可能会有所帮助)?这适用于C ++吗? 给定此代码... float f=3.5; int *pi = (int*)&f; ...和假设sizeof(int) == sizeof(float),做f和*pi有相同的二进制表示/模式?

7
我可以使用NULL代替0值吗?
我可以使用NULL指针替代值0吗? 或这样做有什么问题吗? 例如,例如: int i = NULL; 代替: int i = 0; 作为实验,我编译了以下代码: #include <stdio.h> int main(void) { int i = NULL; printf("%d",i); return 0; } 输出: 0 确实,它给了我这个警告,它本身是完全正确的: warning: initialization makes integer from pointer without a cast [-Wint-conversion] 但结果仍然相同。 我是否会由此陷入“不确定行为”? 可以这样使用NULL吗? NULL在算术表达式中用作数字值有什么问题吗? 在这种情况下,C ++的结果和行为是什么? 我已阅读的答案是什么NULL之间的区别,“\ 0”和0大约之间的区别是什么NULL,\0以及0是的,但我没有从那里简洁的信息,如果是很允许的,也是正确的使用NULL作为在赋值和其他算术运算中使用的值。

5
是否允许编译器优化堆内存的分配?
考虑使用以下简单代码new(我知道没有delete[],但是与这个问题无关): int main() { int* mem = new int[100]; return 0; } 是否允许编译器优化new调用? 在我的研究中,g ++(5.2.0)和Visual Studio 2015不能优化new调用,而clang(3.0+)可以优化调用。所有测试均已启用了全部优化功能(对于g ++和clang为-O3,对于Visual Studio为Release模式)。 是不是 new幕后进行系统调用,从而使编译器无法(而且是非法的)优化它吗? 编辑:我现在已经从程序中排除了未定义的行为: #include <new> int main() { int* mem = new (std::nothrow) int[100]; return 0; } clang 3.0不再优化了,但是更高版本。 编辑2: #include <new> int main() { int* mem = new (std::nothrow) int[1000]; …

5
在C / C ++中进行无符号左移之前的掩盖是否过于偏执?
这个问题的动机是由我在C / C ++中实现加密算法(例如SHA-1),编写与平台无关的可移植代码以及彻底避免未定义的行为引起的。 假设标准的加密算法要求您实现此目的: b = (a << 31) & 0xFFFFFFFF 其中a和b是无符号的32位整数。注意,在结果中,我们丢弃了最低有效32位以上的任何位。 作为第一个幼稚的近似值,我们可以假设int在大多数平台上该宽度为32位,因此我们可以这样写: unsigned int a = (...); unsigned int b = a << 31; 我们知道该代码不会在任何地方都起作用,因为int在某些系统上为16位宽,在其他系统上为64位,甚至可能为36位。但是使用stdint.h,我们可以使用以下uint32_t类型来改进此代码: uint32_t a = (...); uint32_t b = a << 31; 这样我们就完成了,对吧?这就是我多年以来的想法。... 不完全的。假设在某个平台上,我们有: // stdint.h typedef unsigned short uint32_t; 在C / C ++中执行算术运算的规则是,如果类型(例如short)比窄int,则将其扩展到int所有值都适合的范围,unsigned int否则。 …

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.