2016-11-11 39 views
-1

这里是我的代码从一个字节数组反序列化uint64_t中值:编译器警告有关未定义操作

uint8_t* s = blah; 

uint64_t output = 
    (((uint64_t)*s++) << 56) + 
    (((uint64_t)*s++) << 48) + 
    (((uint64_t)*s++) << 40) + 
    (((uint64_t)*s++) << 32) + 
    (((uint64_t)*s++) << 24) + 
    (((uint64_t)*s++) << 16) + 
    (((uint64_t)*s++) << 8) + 
    (((uint64_t)*s)  ); 

我编译此代码使用g ++在Ubuntu版本5.4。

虽然代码工作完全按照预期,我得到的最后一行编译时警告:

warning: operation on 's' may be undefined [-Wsequence-point] 

想知道什么可能是错误的,我怎么能解决这个问题。问候。

+0

可能的重复https://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points –

+0

各种's ++'子表达式的评估顺序是未指定的。在这种情况下,同一个对象被多次修改,这个标准不仅仅是说它们可以以任何顺序被评估(这足够糟糕),并且说行为是完全不确定的。 –

+2

任何你不使用简单循环的理由?让编译器进行展开。 – Olaf

回答

3

您的代码对变量s进行了非序列修改。这种行为是未定义的。您可以使用索引,而不是前进的指针修复它(我假设你正在阅读一个little-endian的变量这是不明显的,从你的代码。):

uint64_t output = 
    (((uint64_t)s[0]) << 56) + 
    (((uint64_t)s[1]) << 48) + 
    (((uint64_t)s[2]) << 40) + 
    (((uint64_t)s[3]) << 32) + 
    (((uint64_t)s[4]) << 24) + 
    (((uint64_t)s[5]) << 16) + 
    (((uint64_t)s[6]) << 8) + 
    (((uint64_t)s[7])  ); 
1

你的代码修改的值s七次在指令内,然后第八次使用它。如果C标准或C++标准接收到可能导致此类代码执行或使其执行不可避免的输入,那么C标准或C++标准都不会对其实施什么要求。但是,请注意,如果程序从不接收会导致代码执行不可避免的输入,那么在应用程序中存在此类代码将不会影响应用程序的正确性,因此这不是编译错误。使用s [0],s [1],s [2]等调整代码将使代码更加清晰并避免这些问题。

+0

1)这就是C++,2)C标准清楚地表明这是未定义的行为。 3)C++相同。 – Olaf