C中主要功能的有效签名究竟是什么?我知道:
int main(int argc, char *argv[])
Run Code Online (Sandbox Code Playgroud)
还有其他有效的吗?
我与某人谈论了垮台事件std::stoi.坦率地说,它在std::strtol内部使用,如果报告错误则抛出.但是,根据他们的说法,std::strtol不应该为输入报告错误"abcxyz",导致stoi不抛出std::invalid_argument.
首先,这里有两个在GCC上测试过的关于这些案例行为的程序:
strtol
stoi
他们都表现出成功"123"和失败"abc".
我查看标准以获取更多信息:
§21.5
Throws: invalid_argument if strtol, strtoul, strtoll, or strtoull reports that
no conversion could be performed. Throws out_of_range if the converted value is
outside the range of representable values for the return type.
Run Code Online (Sandbox Code Playgroud)
总结了依赖的行为strtol.那怎么样strtol?我在C11草案中找到了这个:
§7.22.1.4
If the subject sequence is empty or does not have the expected form, no
conversion is performed; the value …Run Code Online (Sandbox Code Playgroud) 现在我们有时必须使用二进制数据.在C++中,我们使用字节序列,因为开头char是我们的构建块.定义为sizeof1,它是字节.char默认情况下,所有库I/O函数都使用.一切都很好,但总是有一点担心,有点奇怪,一些人的错误 - 一个字节中的位数是实现定义的.
所以在C99中,决定引入几个typedef让开发人员轻松表达自己的固定宽度整数类型.当然可选,因为我们从不想伤害便携性.其中uint8_t,迁移到C++ 11中std::uint8_t,固定宽度的8位无符号整数类型,对于真正想要使用8位字节的人来说是完美的选择.
因此,开发人员接受了新工具并开始构建库,这些库明确表示它们接受8位字节序列std::uint8_t*,std::vector<std::uint8_t>或者其他方式.
但是,或许经过深思熟虑,标准化委员会决定不要求实施,std::char_traits<std::uint8_t>因此禁止开发人员轻松,便携地实例化,比如说,std::basic_fstream<std::uint8_t>并轻松读取std::uint8_t二进制数据.或许,我们中的一些人不关心字节中的位数并且对它感到满意.
但遗憾的是,两个世界相互冲突,有时您必须将数据作为char*并将其传递给期望的库std::uint8_t*.但是等等,你说,是不是char变量位并std::uint8_t固定为8?它会导致数据丢失吗?
嗯,这里有一个有趣的标准.的char定义为保持正好一个字节和字节是内存的最低可寻址的块,所以用比特宽度比的较小不能有一个类型char.接下来,它被定义为能够保存UTF-8代码单元.这给了我们最小--8位.所以现在我们有一个typedef,它要求是8位宽,并且是一个至少8位宽的类型.但有其他选择吗?是的,unsigned char.请记住,签名char是实现定义的.还有其他任何一种 谢天谢地,没有.所有其他整数类型都需要超出8位的范围.
最后,std::uint8_t是可选的,这意味着如果未定义使用此类型的库将无法编译.但如果它编译呢?我可以非常自信地说,这意味着我们在8位字节的平台上CHAR_BIT == 8.
一旦我们有这方面的知识,我们已经8位字节,这std::uint8_t是实现为char或者unsigned char,我们可以假设,我们可以做reinterpret_cast的char*到std::uint8_t*,反之亦然?它是便携式的吗?
这是我的Standardese阅读技巧让我失望的地方.我读了关于安全派生的指针([basic.stc.dynamic.safety]),据我所知,以下内容:
std::uint8_t* buffer = /* ... */ ;
char* buffer2 …Run Code Online (Sandbox Code Playgroud) 介绍
随着C++ 14(又名C++ 1y)标准处于接近最终的状态,程序员必须问自己有关向后兼容性以及与此相关的问题.
这个问题
在该问题的答案中,指出该标准有一个附录,专门用于有关修订之间变化的信息.
如果可以解释前面提到的附录中的这些潜在问题,或许在任何与那里提到的相关的正式文件的帮助下,将会有所帮助.
这是这个问题的后续问题:声明constexpr initializer_list对象是否合法?.
从C++ 14开始,std::initializer_list该类的所有方法都标有constexpr.能够通过执行来初始化实例似乎很自然,
constexpr std::initializer_list<int> list = {1, 2, 3};
但是Clang 3.5抱怨list没有被常量表达式初始化.
正如dyp在评论中指出的那样,任何std::initializer_list文字类型的要求似乎都从规范中消失了.
如果我们甚至不能将类完全定义为constexpr,那么有什么意义呢?这是标准中的疏忽,将来会得到修复吗?
我不小心写了这样的代码:
foo = [42]
k = {'c': 'd'}
for k['z'] in foo: # Huh??
print k
Run Code Online (Sandbox Code Playgroud)
但令我惊讶的是,这不是语法错误.相反,它打印{'c': 'd', 'z': 42}.
我的猜测是代码翻译成字面意思:
i = iter(foo)
while True:
try:
k['z'] = i.next() # literally translated to assignment; modifies k!
print k
except StopIteration:
break
Run Code Online (Sandbox Code Playgroud)
但是......为什么语言允许这样做?我希望在for-stmt的目标表达式中只允许使用单个标识符和标识符元组.是否存在实际有用的情况,而不仅仅是一个奇怪的问题?
最近我遇到了这个问题:分配运营商链理解.
在回答这个问题,我开始怀疑我自己的加法赋值运算符的行为的理解+=或任何其他operator=(&=,*=,/=等).
我的问题是,a下面的表达式中的变量何时更新到位,以便在评估期间其更改的值反映在表达式的其他位置,它背后的逻辑是什么?请看下面两个表达式:
表达1
a = 1
b = (a += (a += a))
//b = 3 is the result, but if a were updated in place then it should've been 4
Run Code Online (Sandbox Code Playgroud)
表达2
a = 1
b = (a += a) + (a += a)
//b = 6 is the result, but if a is not updated in place then it should've been 4
Run Code Online (Sandbox Code Playgroud)
在第一个表达式中,当(a …
struct A
{
~A() = delete;
};
int main()
{
new A{};
}
Run Code Online (Sandbox Code Playgroud)
这无法编译,并显示错误消息:
错误:使用已删除的函数'A :: ~A()'new A {};
据我所知,我没有破坏对象,为什么它试图调用析构函数?
用GCC 8.1.0编译
g++ -std=c++17 -O2
Run Code Online (Sandbox Code Playgroud) 在检查另一个问题的引用时,我注意到C++ 11中的一个奇数子句,在[expr.rel]3:
指针
void(后指针转化)可以进行比较,以确定其结果如下:如果两个指针表示相同的地址或均为空指针值,其结果是true,如果操作者<=或>=与false其他方式; 否则结果未指定.
这似乎意味着,一旦两个指针被投入void *,它们的排序关系就不再有保证; 例如,这个:
int foo[] = {1, 2, 3, 4, 5};
void *a = &foo[0];
void *b = &foo[1];
std::cout<<(a < b);
Run Code Online (Sandbox Code Playgroud)
似乎没有具体说明.
有趣的是,这个子句在C++ 03中不存在并且在C++ 14中消失了,所以如果我们采用上面的例子并应用C++ 14的措辞,我会说3.1
- 如果两个指针指向同一数组的不同元素或其子对象,则指向具有较高下标的元素的指针比较大.
将应用,作为a并b指向同一数组的元素,即使它们已被转换为void *.请注意,3.1的措辞在C++ 11中几乎完全相同,但似乎被该void *子句覆盖了.
我的理解是对的吗?在C++ 11中添加并立即删除的奇怪子句有什么意义?或者它可能仍然存在,但是被标准的其他部分移动/隐含?
请考虑以下程序(请参阅此处的实时演示).
#include <stdio.h>
int main(void)
{
int ; // Missing variable name
puts("Surprise");
}
Run Code Online (Sandbox Code Playgroud)
我的编译器gcc 4.8.1给出了以下警告:
[警告]空声明中无用的类型名称[默认启用]
为什么编译好?我不应该得到编译错误吗?当我将它编译为C++程序时,g ++ 4.8.1给出以下错误:
[错误]声明没有声明任何内容[-fpermissive]