问题标签 [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 回答
13651 浏览

c++ - `long` 是否保证至少为 32 位?

通过阅读 C++ 标准,我一直理解 C++ 中的整数基本类型的大小如下:

我从 3.9.1/2 推断出:

  1. 有四种有符号整数类型:“signed char”、“short int”、“int”和“long int”。在此列表中,每种类型提供的存储空间至少与列表中它前面的类型一样多。普通整数具有执行环境架构所建议的自然大小

此外,char3.9.1/ 的大小描述为:

  1. [...] 大到足以存储实现的基本字符集的任何成员。

1.7/1 更具体地定义了这一点:

  1. C++ 内存模型中的基本存储单元是字节。一个字节至少大到足以包含基本执行字符集的任何成员,并且由连续的位序列组成,其数量由实现定义。

这使我得出以下结论:

wheresizeof告诉我们该类型有多少字节。此外,实现定义了一个字节中有多少位。我们大多数人可能习惯于处理 8 位字节,但标准说n一个字节中有位。


这篇文章中,Alf P. Steinbach 说:

long 保证(至少)32位。

这违背了我所理解的根据标准在 C++ 中的基本类型的大小。通常我会认为这是一个初学者的错误,但由于这是 Alf,我认为值得进一步调查。

那么,你说什么?标准是否保证 long 至少为 32 位?如果是这样,请具体说明如何做出此保证。我只是没看到。

  1. C++ 标准明确规定,要了解 C++,您必须了解 C (1.2/1) 1

  2. longC++ 标准隐式定义了 a可以容纳的值的最小限制为LONG_MIN- LONG_MAX 2

所以无论 along有多大,它都必须足够大,才能将 LONG_MIN 保持到 LONG_MAX。

但是 Alf 和其他人特别指出 long 必须至少为 32 位。这就是我要建立的。C++ 标准明确规定字节中的位数未指定(可能是 4、8、16、42)那么如何从能够容纳这些数字LONG_MIN-LONG_MAX到至少 32 位建立连接?


(1) 1.2/1:以下参考文件对于本文件的应用是必不可少的。对于注明日期的参考文献,仅引用的版本适用。对于未注明日期的引用文件,引用文件的最新版本(包括任何修改)适用。

  • ISO/IEC 2382(所有部分),信息技术 – 词汇
  • ISO/IEC 9899:1999,编程语言 - C
  • ISO/IEC 10646-1:2000,信息技术 – 通用多字节编码字符集 (UCS) – 第 1 部分:体系结构和基本多语言平面

(2) 定义<climits>为:

0 投票
2 回答
1871 浏览

c++ - (++i)++ 是未定义的行为吗?

(++i)++未定义的行为吗?在检索增量对象以进行后缀增量操作后,前缀增量的副作用是否可能发生?这对我来说似乎很奇怪。

我的直觉说这在 C++03 中是未定义的,在 C++11 中是明确定义的。我对吗?

0 投票
2 回答
1548 浏览

c++ - `basic_streambuf::setbuf`的效果

我的问题如下:Martin Yorkthisthisthis中声称可以stringstream通过使用如下方式从某个内存中进行读取basic_stringbuf::pubsetbuf

不幸的是,我挖掘了整个标准,看不到它可以保证在哪里工作。我看到的是这只是实现定义的。事实上,在 Microsoft 的实现(也许对其他人也是)这个调用没有任何效果。

以下是我在上一个 C++0x 草案中找到的相关引用。对于basic_streambuf::setbuf[streambuf.virt.buffer]:

1效果:影响流缓冲的方式为本条款(27.8.1.4、27.9.1.5)中从 basic_streambuf 派生的每个类单独定义。

2默认行为: 什么都不做。返回这个。

然而,在派生类中,它似乎保留了行为实现定义。因为basic_stringbuf::setbuf它说[stringbuf.virtuals]:

1效果: 实现定义,除了 setbuf(0,0) 没有效果。

因为basic_filebuf::setbuf它说[filebuf.virtuals]:

12效果:如果 setbuf(0,0) [...],则流变为无缓冲。否则结果是实现定义的。“无缓冲” [...]

就是这样。所以正如我所看到的,一个有效的实现可以完全忽略这些调用(对于非空参数)。

我错了吗?标准的正确解释是什么?C++98/03/0x 有同样的保证吗?您是否有更多关于上述代码在哪些实现上起作用以及在哪些实现上不起作用的统计数据?basic_streambuf::setbuf打算如何使用?

0 投票
4 回答
139357 浏览

c++ - 可以空引用吗?

这段代码是否有效(和定义的行为)?

g++ 和 clang++ 都在没有任何警告的情况下编译它,即使使用-Wall, -Wextra, -std=c++98, -pedantic, -Weffc++...

当然引用实际上不是空的,因为它不能被访问(这意味着取消对空指针的引用),但是我们可以通过检查它的地址来检查它是否为空:

0 投票
4 回答
1238 浏览

c++ - Legality of using operator delete on a pointer obtained from placement new

I'm dang certain that this code ought to be illegal, as it clearly won't work, but it seems to be allowed by the C++0x FCD.

Maybe one of you language lawyers can explain how the standard forbids this.

There's also an array form:

This is the closest question I was able to find.

EDIT: I'm just not buying the argument that the standard's language restricting arguments to function void ::operator delete(void*) apply in any meaningful way to the operand of delete in a delete-expression. At best, the connection between the two is extremely tenuous, and a number of expressions are allowed as operands to delete which are not valid to pass to void ::operator delete(void*). For example:

I hope this shows that whether a pointer may be passed to void operator delete(void*) has no bearing on whether that same pointer may be used as the operand of delete.

0 投票
3 回答
12555 浏览

c++ - 在 typedef 和 new 中使用 typename 关键字

考虑这段代码,

在上面的代码中,typename编译器需要关键字,以便它可以在模板中消除嵌套类型和嵌套值之间的歧义。这意味着,在没有typename关键字的情况下,编译器会将其解释为 T::X 与 x 的乘积,

因此,在可能出现歧义的情况下,关键字typename成为必要,以消除歧义。但是,上下文本身消除歧义的情况很少。另一个主题讨论了基类和函数参数的上下文(尽管后者并没有消除歧义)。在这个话题中,我特别想讨论其他两个似乎没有歧义的上下文,但我们仍然需要写typename

在这两种情况下,关键字typedefnew让编译器清楚地知道后面的内容是type而不是 value

所以我的问题是,为什么编译器仍然需要typename关键字,即使在明确的情况下,例如我们使用typedefand时new


编辑(在阅读了Johannes Schaub的回复后):

这种语法要求我稍微修改一下我的问题,以便其他人可以看到我试图提出的观点。

考虑到这一点,

因此,从上下文来看,编译器仍然很清楚 T::X 是一种类型,无论它出现在 之前 typedef还是之后 typedef除非 C++ 允许我们写typedef 5 five or typedef T::value t_value(其中 T::value 是value),否则typedef它本身的存在消除了所有歧义,因此,typename标准似乎是不必要的要求(在这种情况下)。同样的论点也适用new


另外,我编写了一个使用这个结构作为模板参数的类模板:

我特别想知道以下代码(来自构造函数)是否正确(可移植),

完整的代码ideone。回复前请看一下。:-)

0 投票
5 回答
295 浏览

c++ - 在 C++ 中手动模拟删除运算符的效果是否正式非法?

我意识到这是不明智的,我不打算这样做,但我很好奇以下内容是否实际上是非法的:

我的理解delete x;是相当于调用析构函数然后调用::operator delete(x);,但是我按照标准手动这样做合法吗?我知道在使用新位置时这是一个有效的事情,但是在非位置的情况下呢?我的预感是它可能是非法的,因为delete(而不是operator delete)必须为 each 执行new,但我很想知道。

0 投票
2 回答
1689 浏览

c++ - 基类的“默认”访问说明符差异的基本原理

我知道C++structclassC++ 之间几乎没有区别。我也理解少数差异的原因。像这个,

  • struct 的成员默认是 public 的;类的成员 默认是私有的struct 的成员默认是 public 的原因是为了C++-struct兼容C-struct. 而类成员之所以默认是私有的,是为了引入数据封装的概念(即执行面向对象的原则/技术/等)。

我不明白的是,引用标准 $11.2/2 [class.access.base]

如果基类没有访问说明符,则在派生类声明为 struct 时假定为 public,而在声明类时假定为 private。

这种扭曲和反统一的理由是什么?为什么需要这种差异?

标准中的示例,

这里 B 是 D2、D4 和 D6 的公共基础,D1、D3 和 D5 的私有基础,以及 D7 和 D8 的受保护基础。


编辑

你们中的一些人可能会说,鉴于 struct 和 class 的默认访问权限不同(上面的要点中给出的差异),这种差异是有意义的。但我认为,inherited-struct完全不兼容C-struct(不支持继承),无论你如何派生它。不过我可能是错的。这就是为什么我正在寻求好的解释,可能还有例子!:-)

0 投票
2 回答
320 浏览

c++ - 显式成员特化

g++ 3.4.5 接受此代码:

但我不确定它实际上是合法的 C++03。尤其,

[14.7p3] 在类模板、类模板的成员或类成员模板的显式特化声明中,显式特化的类的名称应为模板 ID。

这个要求是说在这个例子的最后必须使用非 typedef 版本吗?还是我误解了什么?

编辑:进一步的证据:缺陷报告 403表明将类型(在该上下文中,函数调用表达式的参数类型)说成是模板 ID是不正确的,因为模板 ID具有句法含义,而不是语义一。后来的标准草案在 3.4.2中使用了“类模板专业化”而不是“模板 ID ”。

这支持了这样的论点,即尽管A<B>C表示相同的类型(并且具有相同或几乎相同的语义含义),但A<B>它是一个模板 IDC不是,因为术语模板 ID将句法内容指代为一系列标记而不是这些标记的含义。

0 投票
6 回答
2007 浏览

c - printf("%x",1) 会调用未定义的行为吗?

根据C标准(6.5.2.2第6段)

如果表示被调用函数的表达式的类型不包含原型,则对每个参数执行整数提升,而浮点类型的参数将提升为双精度。这些称为默认参数提升。如果参数的数量不等于参数的数量,则行为未定义。如果函数定义为包含原型的类型,并且原型以省略号 (, ...) 结尾,或者提升后的参数类型与参数类型不兼容,则行为未定义。如果函数定义的类型不包含原型,并且提升后的参数类型与提升后的参数类型不兼容,则行为未定义,但以下情况除外:

  • 一种提升类型是有符号整数类型,另一种提升类型是对应的无符号整数类型,并且值可以在两种类型中表示;
  • 这两种类型都是指向字符类型或 void 的限定或非限定版本的指针。

因此,一般来说,只要传递的值适合这两种类型,将 an 传递int给期望 an unsigned int(反之亦然)的可变参数函数没有任何问题。但是,printf阅读规范(7.19.6.1 第 9 段):

如果转换规范无效,则行为未定义。如果任何参数不是相应转换规范的正确类型,则行为未定义。

有符号/无符号不匹配也不例外。

这是否意味着printf("%x", 1)调用未定义的行为?