问题标签 [language-lawyer]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
5 回答
11617 浏览

c++ - Pedantic:什么是源文件?什么是标题?

出于这个问题的目的,我只对符合标准的 C++ 感兴趣,而不是 C 或 C++0x,也不对任何特定于实现的细节感兴趣。

#include ""关于和之间的区别的问题不时出现#include <>。该论点通常归结为两个差异:

  1. 具体实现往往会为这两种形式搜索不同的路径。这是特定于平台的,不在此问题的范围内。
  2. 该标准说#include <>是针对“标题”,而#include ""针对“源文件”。以下是相关参考:

ISO/IEC 14882:2003(E)

16.2 源文件包含[cpp.include]

1 #include 指令应标识可由实现处理的头文件或源文件。

2形式的预处理指令

在一系列实现定义的位置中搜索由 < 和 > 分隔符之间的指定序列唯一标识的标头,并用标头的全部内容替换该指令。如何指定位置或标识的标头是实现定义的。

3形式的预处理指令

导致将该指令替换为由 " 分隔符之间的指定序列标识的源文件的全部内容。以实现定义的方式搜索命名的源文件。如果不支持此搜索,或者搜索失败, 该指令被重新处理,就好像它读取 具有与原始指令相同的包含序列(包括 > 字符,如果有的话)。

(上面引用的重点是我的。)这种差异的含义似乎是标准打算区分“标题”和“源文件”,但文档没有定义这些术语或它们之间的区别.

很少有其他地方甚至提到头文件或源文件。一些:

158)标题不一定是源文件,由标题名称分隔的序列也不一定是有效的源文件名(16.2)。

似乎暗示头文件可能不驻留在文件系统中,但它也没有说源文件存在。

2 词汇约定 [lex]

1程序文本保存在本国际标准中称为源文件的单元中。源文件连同通过预处理指令包含的所有头文件 (17.4.1.2) 和源文件 (16.2) #include,减去由任何条件包含 (16.1) 预处理指令跳过的任何源代码行,称为翻译单元。[注意:一个 C++ 程序不需要同时翻译。]

这是我能找到的最接近定义的,它似乎暗示标题不是“程序的文本”。但是如果你#include是一个标题,它不会成为程序文本的一部分吗?这有点误导。

那么什么是标头?什么是源文件?

0 投票
1 回答
1085 浏览

c - C中的隐式声明

以下程序是否Undefined Behaviour在 C 中调用?

在上面的程序中有一个隐式声明printf(),那么上面的代码是完全符合标准的还是它只是有一些特定于实现的行为?

0 投票
8 回答
15845 浏览

c++ - 优化“while(1);” 在 C++0x 中

已更新,见下文!

我听说并读到 C++0x 允许编译器为以下代码段打印“Hello”

它显然与线程和优化能力有关。在我看来,这可能会让很多人感到惊讶。

有人对为什么有必要允许这样做有很好的解释吗?作为参考,最新的 C++0x 草案在6.5/5

在 for 语句的情况下,在 for-init 语句之外的循环,

  • 不调用库 I/O 函数,并且
  • 不访问或修改易失性对象,并且
  • 不执行同步操作(1.10)或原子操作(第 29 条)

可以假定由实现终止。[ 注意:这旨在允许编译器转换,例如删除空循环,即使无法证明终止也是如此。——尾注]

编辑:

这篇有见地的文章谈到了标准文本

不幸的是,没有使用“未定义的行为”一词。但是,只要标准说“编译器可能假定 P”,就暗示具有非 P 属性的程序具有未定义的语义。

这是正确的,编译器是否允许为上述程序打印“Bye”?


这里有一个更有洞察力的线程,它是关于对 C 的类似更改,由完成上述链接文章的 Guy 开始。在其他有用的事实中,他们提出了一个似乎也适用于 C++0x 的解决方案(更新:这将不再适用于 n3225 - 见下文!)

似乎不允许编译器对其进行优化,因为它不是循环,而是跳转。另一个人总结了 C++0x 和 C201X 中的提议更改

通过编写循环,程序员要么断言循环做了一些具有可见行为的事情(执行 I/O、访问易失性对象,或者执行同步或原子操作), 要么它最终终止。如果我通过编写一个没有副作用的无限循环来违反该假设,那么我就是在对编译器撒谎,并且我的程序的行为是未定义的。(如果我很幸运,编译器可能会警告我。)该语言不提供(不再提供?)一种在没有可见行为的情况下表达无限循环的方法。


更新 3.1.2011 与 n3225:委员会将文本移至 1.10/24 并说

实现可能假设任何线程最终都会执行以下操作之一:

  • 终止,
  • 调用库 I/O 函数,
  • 访问或修改 volatile 对象,或
  • 执行同步操作或原子操作。

这个goto技巧将不再起作用!

0 投票
4 回答
8882 浏览

c - 限制 C 中 main 的参数数量

我们在 C 中传递的参数数量是否有限制main()?众所周知,它被定义为int main(int argc, char *argv[])

当我调用程序时,我可以像这样传递参数:

我们可以通过这种方式提供的参数数量是否有上限main()

0 投票
8 回答
20653 浏览

c++ - 为什么当左侧操作数为负值时,左移操作会调用未定义行为?

在 C 中,当左侧操作数为负值时,按位左移操作调用未定义行为。

来自 ISO C99 (6.5.7/4) 的相关引用

E1 << E2 的结果是 E1 左移 E2 位位置;空出的位用零填充。如果 E1 具有无符号类型,则结果的值为 E1 × 2 E2,以比结果类型中可表示的最大值多一个模数减少。如果 E1 有带符号类型和非负值,并且 E1 × 2 E2在结果类型中是可表示的,那么这就是结果值;否则,行为未定义

但是在 C++ 中,行为是明确定义的。

ISO C++-03 (5.8/2)

E1 << E2 的值是 E1(解释为位模式)左移 E2 位位置;空出的位用零填充。如果 E1 具有无符号类型,则结果的值是 E1 乘以 2 的 E2 次幂,如果 E1 具有无符号长类型,则以模 ULONG_MAX+1 减少,否则为 UINT_MAX+1。[注意:常量 ULONG_MAX 和 UINT_MAX 在标题中定义)。]

这意味着

在 C 中调用未定义的行为,但该行为在 C++ 中定义良好。

是什么迫使 ISO C++ 委员会认为这种行为与 C 中的行为相反?

另一方面,implementation defined当左操作数为负时,行为是按位右移操作,对吗?

我的问题是为什么左移操作会调用 C 中的未定义行为,为什么右移运算符只调用实现定义的行为?

PS:请不要给出“这是未定义的行为,因为标准是这样说的”这样的答案。:P

0 投票
2 回答
3542 浏览

c++ - 未排序的值计算(又名序列点)

很抱歉再次打开这个话题,但是考虑这个话题本身已经开始给我一个未定义的行为。想要进入定义明确的行为区域。

给定

我认为上述表达式(按此顺序)为

现在谈到这里的行为是来自C++ 0x的重要引述。

$1.9/12-“表达式(或子表达式)的评估通常包括值计算(包括确定对象的身份以进行左值评估和获取先前分配给对象以进行右值评估的值)和副作用的启动。”

$1.9/15-“如果标量对象的副作用相对于同一标量对象的另一个副作用使用同一标量对象的值的值计算是未排序的,则行为未定义。”

[注意:与不同参数表达式相关的值计算和副作用是无序的。——尾注]

$3.9/9-“算术类型 (3.9.1)、枚举类型、指针类型、指向成员类型的指针 (3.9.2)、std::nullptr_t 和这些类型的 cv 限定版本 (3.9.3) 统称为标量类型。”

  • 在 Expr1 中,表达式i(第一个参数)的评估相对于表达式的评估operator++(i)(具有副作用)是无序的。

    因此 Expr1 具有未定义的行为。

  • 在 Expr2 中,表达式i(第一个参数)的评估相对于表达式operator++(i, 0)(具有副作用)的评估是无序的。

    因此 Expr2 具有未定义的行为。

  • 在 Expr3 中,operator++(i)需要在调用外部参数之前完成对单独参数的评估operator++

    因此,Expr3 具有明确定义的行为。

  • 在 Expr4 中,表达式i(第一个参数)的计算相对于operator[](operator++(i, 0)(有副作用)的计算是无序的。

    因此 Expr4 具有未定义的行为。

这种理解正确吗?


PS OP中分析表达式的方法不正确。这是因为,正如@Potatoswatter 所指出的那样 - “第 13.6 条不适用。请参阅 13.6/1 中的免责声明,“这些候选函数参与 13.3.1.2 中所述的运算符重载解决过程,并且不用于其他目的。 “它们只是虚拟声明;不存在与内置运算符相关的函数调用语义。”

0 投票
4 回答
23506 浏览

c - C中负数的表示?

C如何表示负整数?

是通过二进制补码表示还是使用 MSB(最高有效位)?

-1十六进制是ffffffff.

所以请为我澄清这一点。

0 投票
3 回答
431 浏览

c++ - ISO C中数组的左值到右值转换

C++ ANSI ISO IEC 14882 2003 附录 C.1(第 668 页):

变化:条件表达式、赋值表达式或逗号表达式的结果可能是 bean 左值
理由:C++ 是一种面向对象的语言,相对更强调左值。例如,函数可能返回左值。
对原始特征的影响:改变定义明确的特征的语义。一些隐式依赖左值到右值转换的 C 表达式会产生不同的结果。例如,

在 C++ 和 C 中产生sizeof(char*)100.
...

我今天刚读到这篇文章,我记得几个月前我的一个朋友提出了一个问题,即编写一个函数,如果用 C++ 编译将返回 0,如果用 C 编译则返回 1。我解决了它利用了在 C 中结构位于外部范围内的事实。因此,考虑到这些新信息,我决定这将是上述问题的另一种解决方案,我在 Microsoft Visual Studio 2008 上尝试过,但无论它是编译为 C 还是 C++ 代码sizeof(0, arr)总是产生 4。所以 2 个问题:

1.什么是ISO C?它是当前的 C 标准吗?它是唯一的吗(我听说 C 正在迅速发展) 2. 这是微软 C++ 的错误吗?

TIA

编辑:抱歉混淆了输出并对其进行了编辑:

0 投票
7 回答
4352 浏览

c++ - 联合作为基类

该标准定义了 Unions 不能用作 Base 类,但是对此有什么具体的理由吗?据我了解,联合可以有构造函数、析构函数、成员变量以及对这些变量进行操作的方法。简而言之,Union 可以封装可以通过成员函数访问的数据类型和状态。因此,在最常见的术语中,它有资格成为一个类,如果它可以作为一个类,那么为什么限制它不能作为一个基类呢?

编辑:虽然答案试图解释原因,但我仍然不明白 Union 作为派生类比 Union 作为一个类更糟糕。因此,为了获得更具体的答案和推理,我将推动这个以获得赏金。对已经发布的答案没有冒犯,谢谢!

0 投票
1 回答
634 浏览

c++ - 匿名的空未标记类、结构、联合和枚举

!免责声明!: 请注意,我说的是未标记的声明。我知道这可能是一个非正式的术语,我的意思是声明不是 typedef 并且它没有声明匿名类型的对象。在这些情况下,一切都很清楚。

问题1:
以下哪个是格式良好的C++程序?(多项选择)

备注:
MSVC9.0 接受这三个。在第一个它发出警告。在第二个和第三个上,我们得到 0 个错误和 0 个警告。在线喜剧只接受第三个,第一个和第二个无法编译并带有诊断消息“声明没有声明任何内容”。如果在第二个中,匿名枚举包含至少一个枚举数,那么第二个被 comeau 编译器正确地接受。

如果 comeau 编译器是正确的,并且这是标准行为,那么我会发现其中有些不一致。我能理解为什么第一名应该被拒绝。我也会理解为什么第二个应该被拒绝(什么都不声明),但在这种情况下,第三个也应该被拒绝。如果不应该拒绝第三个,那么我看到的与第一个的唯一区别是匿名工会成员的范围是外部范围。但是枚举也是如此,所以,我的主张是应该接受第三个,然后应该接受第二个。

问题2:
如果comeau是正确的,我在上述判断中缺少什么考虑?

PS我已经写了一封电子邮件给comeau支持。我一得到答案就会发布他们的答案。