我有点好奇创建一个宏来为设备寄存器生成位掩码,最高可达64位.这样就BIT_MASK(31)产生了0xffffffff.
但是,有几个C示例不能像我想的那样工作,而是我得到的0x7fffffff.这是因为编译器假设我想要签名输出,而不是无符号输出.所以我尝试了32,并注意到该值回绕到0.这是因为C标准声明如果移位值大于或等于要移位的操作数中的位数,则结果是未定义的.那讲得通.
但是,鉴于以下计划,bits2.c:
#include <stdio.h>
#define BIT_MASK(foo) ((unsigned int)(1 << foo) - 1)
int main()
{
unsigned int foo;
char *s = "32";
foo = atoi(s);
printf("%d %.8x\n", foo, BIT_MASK(foo));
foo = 32;
printf("%d %.8x\n", foo, BIT_MASK(foo));
return (0);
}
Run Code Online (Sandbox Code Playgroud)
如果我编译gcc -O2 bits2.c -o bits2,并在Linux/x86_64机器上运行它,我得到以下内容:
32 00000000
32 ffffffff
Run Code Online (Sandbox Code Playgroud)
如果我使用相同的代码并在Linux/MIPS(big-endian)机器上编译它,我得到这个:
32 00000000
32 00000000
Run Code Online (Sandbox Code Playgroud)
在x86_64机器上,如果我使用gcc -O0 bits2.c -o bits2,那么我得到:
32 00000000
32 00000000
Run Code Online (Sandbox Code Playgroud)
如果我调整BIT_MASK到 …
i在我的程序中,我发现当is时循环无法正确退出int32_t。看起来像是整数溢出,并且远大于10,并且循环不会停止。请告诉我发生了什么以及如何在大型项目中避免此错误。
#include <iostream>
#include <stdint.h>
int f(int n){
for (int32_t i = 0; i < 10; ++i)
{
int64_t time = 4500000000 + (i) * 500000000;
std::cout << time<< " i: " << i << std::endl;
}
return 0;
}
int main ()
{
return f(10);
}
Run Code Online (Sandbox Code Playgroud)
我想知道x在以下程序中是否会达到零.
请考虑:
int main ()
{
int x = 1;
while (x)
{
x <<= 1;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该程序的预期行为是正常退出还是永远循环?
几天前,我遇到了我认为是g ++ 5.3中有关在更高-OX优化级别嵌套for循环的错误.(专门为它-O2而经历过-O3).问题是,如果你有两个嵌套的for循环,它有一些内部和来跟踪总迭代次数,一旦这个总和超过它的最大值,就会阻止外部循环终止.我能够复制的最小代码集是:
int main(){
int sum = 0;
// Value of 100 million. (2047483648 less than int32 max.)
int maxInner = 100000000;
int maxOuter = 30;
// 100million * 30 = 3 billion. (Larger than int32 max)
for(int i = 0; i < maxOuter; ++i)
{
for(int j = 0; j < maxInner; ++j)
{
++sum;
}
std::cout<<"i = "<<i<<" sum = "<<sum<<std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
当使用g++ -o run.me main.cpp它编译时,它按预期输出运行:
i = …Run Code Online (Sandbox Code Playgroud) 我是位操作技巧的新手,我写了一个简单的代码来查看在单个数字上进行单个位移的输出. 2
#include <iostream>
int main(int argc, char *argv[])
{
int num=2;
do
{
std::cout<<num<<std::endl;
num=num<<1;//Left shift by 1 bit.
} while (num!=0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出如下.
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768
65536
131072
262144
524288
1048576
2097152
4194304
8388608
16777216
33554432
67108864
134217728
268435456
536870912
1073741824
-2147483648
Run Code Online (Sandbox Code Playgroud)
显然,连续比特移位到左边由1个比特,将导致零,因为它已经在上面进行,但为什么计算机输出一个负数在最后终止在循环之前(自NUM接通零)??
然而,当我替换时int num=2,unsigned int num=2我获得相同的输出,除了最后一个数字是这个时间显示为正,2147483648而不是-2147483648
我gcc在Ubuntu Linux上使用编译器
我写了很多处理消息协议的代码。消息协议通常会具有通用的消息帧,可以从串行端口或套接字反序列化。该帧包含消息类型,并且必须根据消息类型来处理消息有效负载。
通常,我用访问器方法和构造函数编写一个多态类集,该构造函数引用消息框。
我想到的是,我可以直接从消息框架派生访问器类,然后从消息框架重新解释_cast到适当的访问器类,而不是基于对消息框架的引用来构造访问器类。这使代码更加简洁,并节省了一些字节和处理器周期。
请参见下面的示例(极度虚构和压缩)。显然,对于生产代码,所有这些都需要适当地封装,强制转换成为派生类的成员,更好地分离了所关注的问题,并添加了一些验证。为了简洁起见,已全部删除。
#include <iostream>
#include <cstring>
#include <vector>
struct GenericMessage
{
GenericMessage(const char* body):body_(body, body+strlen(body)){}
std::vector<char> body_;
};
struct MessageType1:public GenericMessage
{
int GetFoo()const
{
return body_[2];
}
int GetBar()const
{
return body_[3];
}
};
int main()
{
GenericMessage myGenericMessage("1234");
MessageType1* myMgessageType1 = reinterpret_cast<MessageType1*>(&myGenericMessage);
std::cout << "Foo:" << myMgessageType1->GetFoo() << std::endl;
std::cout << "Bar:" << myMgessageType1->GetBar() << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我从来没有见过任何地方这样做。考虑到派生没有其他数据成员,以这种方式从基础到派生有任何不利之处吗?
以下是GNU C参考手册第74页的代码:
如果您的代码使用带符号循环索引,请确保索引不会溢出,以及从索引派生的所有已签名表达式.这是一个有问题的代码的例子,有两个溢出实例.
for( i = INT_MAX - 10 ; i <= INT_MAX; i++)
if( i+1 < 0 ) //first overflow
{
report_overflow();
break;
}
Run Code Online (Sandbox Code Playgroud)
由于存在两个溢出,编译器可能会以与环绕假设不兼容的方式优化或转换两个比较.
为什么这个循环(到10亿)只需要几个声音来执行...
for (i = 0; i < 1000000000; i++)
{
}
Run Code Online (Sandbox Code Playgroud)
...但这个循环(达到100亿)需要> 10分钟?
for (i = 0; i < 10000000000; i++)
{
}
Run Code Online (Sandbox Code Playgroud)
它不应该只需要30秒左右(3秒x 10)?
我正在尝试理解C++数值属性.因此,我对下溢现象感兴趣.任何人都可以给我一个下溢的例子以及如何处理它?
请考虑以下示例:
class Base {
public:
int data_;
};
class Derived : public Base {
public:
void fun() { ::std::cout << "Hi, I'm " << this << ::std::endl; }
};
int main() {
Base base;
Derived *derived = static_cast<Derived*>(&base); // Undefined behavior!
derived->fun();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
根据C++标准,函数调用显然是未定义的行为.但是在所有可用的机器和编译器(VC2005/2008,RH Linux和SunOS上的gcc)上,它按预期工作(打印"嗨!").有谁知道配置此代码可以正常工作?或者可能是具有相同想法的更复杂的例子(注意,Derived不应该携带任何额外的数据)?
更新:
从标准5.2.9/8:
类型"指针CV1 B",其中B是一个类类型的右值,可以转换为类型"指针CV2 d",的右值,其中d是从乙派生的类(第10节),如果一个有效的标准从"指针d"转换到"指针到B"的存在(4.10),CV2是相同cvqualification为或者更大cvqualification比,CV1,和B不是虚拟基类d的空指针值(4.10)转换为目标类型的空指针值.如果类型是"指针CV1 B"点右值进行B实际上是类型d的对象的子对象,将所得指针指向类型D.的包围对象否则,铸造的结果是不确定的.
还有一个9.3.1(感谢@Agent_L):
如果为非X类型的对象或从X派生的类型调用类X的非静态成员函数,则行为未定义.
谢谢,迈克.
c++ ×6
c ×5
bit-shift ×2
for-loop ×2
inheritance ×1
loops ×1
nested-loops ×1
optimization ×1
underflow ×1