我知道C++ 中的"未定义行为"几乎可以让编译器做任何想做的事情.但是,我遇到了让我感到惊讶的崩溃,因为我认为代码足够安全.
在这种情况下,真正的问题仅发生在使用特定编译器的特定平台上,并且仅在启用了优化时才发生.
我尝试了几件事来重现问题并将其简化到最大程度.这是一个名为的函数的摘录Serialize,它将获取bool参数,并将字符串true或复制false到现有的目标缓冲区.
如果bool参数是未初始化的值,那么这个函数是否会在代码审查中,没有办法告诉它实际上可能会崩溃?
// Zero-filled global buffer of 16 characters
char destBuffer[16];
void Serialize(bool boolValue) {
// Determine which string to print based on boolValue
const char* whichString = boolValue ? "true" : "false";
// Compute the length of the string we selected
const size_t len = strlen(whichString);
// Copy string into destination buffer, which is zero-filled (thus already null-terminated)
memcpy(destBuffer, whichString, len);
}
Run Code Online (Sandbox Code Playgroud)
如果使用clang 5.0.0 +优化执行此代码,它将/可能崩溃.
boolValue ? "true" …
这是我的代码:
#include <cstring>
#include <iostream>
int main() {
bool a;
memset(&a, 0x03, sizeof(bool));
if (a) {
std::cout << "a is true!" << std::endl;
}
if (!a) {
std::cout << "!a is true!" << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
它输出:
a is true!
!a is true!
Run Code Online (Sandbox Code Playgroud)
似乎!运算符bool仅反转最后一位,但每个不相等的值0都被视为true.这导致显示的行为,这在逻辑上是错误的.这是实施中的错误,还是规范允许这样做?请注意,memset可以省略,并且行为可能是相同的,因为a包含内存垃圾.
我正在使用gcc 4.4.5,其他编译器可能会采用不同的方式.
什么是C中的陷阱表示(某些示例可能有帮助)?这适用于C++吗?
float f=3.5;
int *pi = (int*)&f;
Run Code Online (Sandbox Code Playgroud)sizeof(int) == sizeof(float)do f和*pi具有相同的二进制表示/模式?MSVC怎么样?如果我得到一个bool变量并将其第二位设置为1,则变量同时评估为true和false。使用带有-g选项(gcc-v6.3.0/Linux/RHEL6.0-2016-x86_64/bin/g++ -g main.cpp -o mytest_d)的gcc6.3编译以下代码,然后运行可执行文件。您得到以下内容。
T如何同时等于真和假?
value bits
----- ----
T: 1 0001
after bit change
T: 3 0011
T is true
T is false
Run Code Online (Sandbox Code Playgroud)
当您使用不同的语言(例如fortran)调用函数时,可能会发生这种情况,其中对和错的定义与C ++不同。对于fortran,如果任何位都不为0,则该值为true;如果所有位为零,则该值为false。
#include <iostream>
#include <bitset>
using namespace std;
void set_bits_to_1(void* val){
char *x = static_cast<char *>(val);
for (int i = 0; i<2; i++ ){
*x |= (1UL << i);
}
}
int main(int argc,char *argv[])
{
bool T = 3;
cout <<" value bits " <<endl;
cout <<" …Run Code Online (Sandbox Code Playgroud) 我正在阅读C++编程语言.Stroustrup在其中陈述sizeof(char) == 1和1 <= sizeof(bool).具体取决于实施.为什么像布尔这样的简单值与char相同?
示例波纹管编译,但输出相当奇怪:
#include <iostream>
#include <cstring>
struct A
{
int a;
char b;
bool c;
};
int main()
{
A v;
std::memset( &v, 0xff, sizeof(v) );
std::cout << std::boolalpha << ( true == v.c ) << std::endl;
std::cout << std::boolalpha << ( false == v.c ) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
输出是:
true
true
Run Code Online (Sandbox Code Playgroud)
有人能解释为什么吗?
如果重要,我使用的是g ++ 4.3.0
在下面的代码中,我memset()是一个stdbool.h bool值变量123.(也许这是未定义的行为?)然后我将指向此变量的指针传递给受害者函数,该函数尝试使用条件操作来防止意外值.但是,由于某种原因,GCC似乎完全取消了条件操作.
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
void victim(bool* foo)
{
int bar = *foo ? 1 : 0;
printf("%d\n", bar);
}
int main()
{
bool x;
bool *foo = &x;
memset(foo, 123, sizeof(bool));
victim(foo);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
user@host:~$ gcc -Wall -O0 test.c user@host:~$ ./a.out 123
使这个特别恼人的是该victim()函数实际上在库中,如果值大于1则会崩溃.
转载于GCC版本4.8.2-19ubuntu1和4.7.2-5.没有在clang上复制.
我正在尝试编写一些用于类型安全使用的宏_Bool,然后对我的代码进行压力测试.出于恶意测试的目的,我想出了这个肮脏的黑客:
_Bool b=0;
*(unsigned char*)&b = 42;
Run Code Online (Sandbox Code Playgroud)
鉴于实现上_Bool有1个字节sizeof(_Bool)==1,我不知道这个hack是如何违反C标准的.它不应该是严格的别名违规.
然而,当通过各种编译器运行此程序时,我遇到了问题:
#include <stdio.h>
int main(void)
{
_Static_assert(sizeof(_Bool)==1, "_Bool is not 1 byte");
_Bool b=0;
*(unsigned char*)&b = 42;
printf("%d ", b);
printf("%d", b!=0 );
return 0;
}
Run Code Online (Sandbox Code Playgroud)
(代码依赖于printf隐式默认参数提升int)
某些版本的gcc和clang给出输出42 42,其他版本给出0 0.即使禁用了优化.我原以为是42 1.
似乎编译器假设_Bool只能是1或者0同时它42在第一种情况下快乐地打印.
Q1:这是为什么?上面的代码是否包含未定义的行为?
Q2:可靠性如何sizeof(_Bool)?C17 6.5.3.4完全没有提及_Bool.