我正在学习未定义的行为,并在没有任何明确解释的情况下偶然发现了这段代码:
#include <stdio.h>
#include <limits.h>
int foo ( int x) {
printf ("% d\n" , x ); //2147483647
printf ("% d\n" , x+1 ); //-2147483648 overflow
return ( x+1 ) > x ; // 1 but How????
}
int main ( void ) {
printf ("% d\n" , INT_MAX ); //2147483647
printf ("% d\n" , INT_MAX+1 ); //-2147483648 overflow
printf ("% d\n" , ( INT_MAX+1 ) > INT_MAX ); //0 makes sense, since -ve < +ve
printf ("% d\n" , …Run Code Online (Sandbox Code Playgroud) 我试图理解C如何在堆栈上分配内存.我一直认为堆栈上的变量可以描述为结构成员变量,它们占用堆栈中连续的,连续的字节块.为了帮助说明我在某个地方发现的这个问题,我创建了这个小程序来重现这个现象.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void function(int *i) {
int *_prev_int = (int *) ((long unsigned int) i - sizeof(int)) ;
printf("%d\n", *_prev_int );
}
void main(void)
{
int x = 152;
int y = 234;
function(&y);
}
Run Code Online (Sandbox Code Playgroud)
看看我在做什么?假设sizeof(int)是4:我在传递的指针后面看了4个字节,因为它会int y在调用者堆栈中的位置之前读取4个字节.
它没有打印152.奇怪的是当我看下4个字节时:
int *_prev_int = (int *) ((long unsigned int) i + sizeof(int)) ;
Run Code Online (Sandbox Code Playgroud)
现在它可以工作,打印x调用者堆栈内的任何内容.为什么x地址低于y?堆栈变量是否颠倒存储?
我有以下结构和"getter"函数,它返回a强制转换为无符号整数:
struct s {
uint32_t a;
};
void get_a(struct s *st, unsigned *ret)
{
*ret = (unsigned)st->a;
}
Run Code Online (Sandbox Code Playgroud)
运行以下代码:
struct s st;
uint16_t x;
st.a = 1;
get_a(&st, (unsigned *)&x);
Run Code Online (Sandbox Code Playgroud)
对于x86_64,i686,armv7hl,ppc64le等架构x == 1,但对于ppc64 x == 0.为什么是这样?Little-vs. big-endian?
据我了解,malloc(x) 返回一个 x 字节长的内存块。
因此,要存储 4 字节整数,我会这样做:
int *p = (int *)malloc(4);
*p = 100;
Run Code Online (Sandbox Code Playgroud)
因为 sizeof(int) 对我返回 4 。
但是,如果我这样做:
int *p = (int *)malloc(1);
*p = 100;
Run Code Online (Sandbox Code Playgroud)
它的工作原理似乎完全相同,存储值没有问题。
为什么使用 malloc() 请求的内存量似乎并不重要?4 字节整数不应该需要 malloc(4) 吗?
我想知道分配给指针的大小.
所以我找到了这个答案: 我怎么知道c中指针变量的分配内存大小
它有以下代码.
#include <stdlib.h>
#include <stdio.h>
void * my_malloc(size_t s)
{
size_t * ret = malloc(sizeof(size_t) + s);
*ret = s;
return &ret[1];
}
void my_free(void * ptr)
{
free( (size_t*)ptr - 1);
}
size_t allocated_size(void * ptr)
{
return ((size_t*)ptr)[-1];
}
int main(int argc, const char ** argv)
{
int * array = my_malloc(sizeof(int) * 3);
printf("%u\n", allocated_size(array));
my_free(array);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这条线(((size_t*)ptr)[-1])很完美,但我不明白为什么......
有人能帮我理解这条神奇的线条吗?谢谢!
我正在学习C,因此尝试了以下代码,并获得了7,6而不是的输出6,7。为什么?
#include <stdio.h>
int f1(int);
void main()
{
int b = 5;
printf("%d,%d", f1(b), f1(b));
}
int f1(int b)
{
static int n = 5;
n++;
return n;
}
Run Code Online (Sandbox Code Playgroud) 我经常需要为“原始”资源句柄(例如文件句柄,Win32 OS句柄等)实现C ++包装。这样做时,我还需要实现move运算符,因为默认的编译器生成的操作符不会清除move-from对象,从而产生双删除问题。
在实现移动分配运算符时,我更喜欢显式调用析构函数,并使用new放置就地重新创建对象。这样,我避免了析构函数逻辑的重复。另外,我经常根据copy + move(在相关时)实现副本分配。这将导致以下代码:
/** Canonical move-assignment operator.
Assumes no const or reference members. */
TYPE& operator = (TYPE && other) noexcept {
if (&other == this)
return *this; // self-assign
static_assert(std::is_final<TYPE>::value, "class must be final");
static_assert(noexcept(this->~TYPE()), "dtor must be noexcept");
this->~TYPE();
static_assert(noexcept(TYPE(std::move(other))), "move-ctor must be noexcept");
new(this) TYPE(std::move(other));
return *this;
}
/** Canonical copy-assignment operator. */
TYPE& operator = (const TYPE& other) {
if (&other == this)
return *this; // self-assign
TYPE copy(other); // may throw
static_assert(noexcept(operator …Run Code Online (Sandbox Code Playgroud) c++ assignment-operator move-semantics move-assignment-operator
根据C标准:
当两个指针相减时,两者都应指向同一数组对象的元素,或指向数组对象最后一个元素的元素(第 6.5.6 1173 节)
[注意:不要假设我对标准或 UB 了解很多,我只是碰巧发现了这个]
现在另一方面
因此我的问题是:从实验来看,似乎在某些体系结构(例如 x86-64)上,两个数组之间的指针差异提供了合理的、可重现的结果。它似乎与这些架构的硬件相当吻合。那么某些实现是否真的确保了特定的行为?
例如,在野外是否有一个实现可以保证a并且b存在char*,我们有a + (reinterpret_cast<std::ptrdiff_t>(b)-reinterpret_cast<std::ptrdiff_t>(a)) == b?
在 GNU Awk 用户指南中,我浏览了6.2.2 字符串连接部分,并发现了有趣的见解:
由于字符串连接没有显式运算符,因此通常需要通过使用括号将要连接的项括起来来确保它在正确的时间发生。
然后,我很惊讶地阅读以下内容:
除了最常见的上下文外,所有的连接都应该使用括号,例如在“=”的右侧。请注意字符串连接中使用的表达式类型。特别是,用于连接的表达式的求值顺序在 awk 语言中是未定义的。考虑这个例子:
Run Code Online (Sandbox Code Playgroud)BEGIN { a = "don't" print (a " " (a = "panic")) }未定义对 a 的第二次赋值是在检索 a 的值以生成连接值之前还是之后。结果可能是“不要惊慌”或“惊慌失措”。
特别是,在我的 GNU Awk 5.0.0 中,它是这样执行的,在打印值之前进行替换:
$ gawk 'BEGIN {a = "dont"; print (a " " (a = "panic"))}'
dont panic
Run Code Online (Sandbox Code Playgroud)
但是,我想知道:为什么没有定义表达式的求值顺序?根据您运行的 Awk 版本的不同,拥有“未定义”的输出有什么好处?
#include <iostream>
#include <stdint.h>
class Test {
public:
Test(const int64_t & val) : val_(val) {
std::cout << "initialized: " << val_ << std::endl;
}
void print() {std::cout << "reference val: " << val_ << std::endl;}
private:
const int64_t & val_;
};
int main() {
long long int input_val= 1628020800000000000L;
auto t = Test(input_val);
std::cout << "input_val: " << input_val << std::endl;
t.print();
}
Run Code Online (Sandbox Code Playgroud)
如果您在没有优化构建的情况下构建,则会得到以下结果:
g++ main.cpp -std=c++17
initialized: 1628020800000000000
input_val: 1628020800000000000
reference val: 1628020800000000000
Run Code Online (Sandbox Code Playgroud)
如果您使用优化构建(例如 -O3)构建,您将获得以下信息:
g++ main.cpp -std=c++17 -O3 …Run Code Online (Sandbox Code Playgroud)