标签: pointer-conversion

C++ 中所有指针的大小都相同吗?

最近,我看到这样的说法

所有指针具有相同的大小是很常见的,但从技术上讲,指针类型具有不同的大小是可能的

但后来我发现了这样的内容:

虽然指针的大小都是相同的,因为它们只存储内存地址,但我们必须知道它们指向什么类型的东西。

现在,我不确定以上哪种说法是正确的。第二个引用的语句看起来像是来自佛罗里达州立大学计算机科学的 C++ 笔记。


这就是为什么在我看来所有指针都应该具有相同的大小:

1)假设我们有:

int i = 0;
void* ptr = &i; 
Run Code Online (Sandbox Code Playgroud)

现在,假设 C++ 标准允许指针具有不同的大小。进一步假设在某些任意机器/编译器上(因为标准允许),a 的void*大小为 2 字节,而 a 的int*大小为 4 字节。

现在,我认为这里有一个问题,即右侧有一个int*大小为 4 字节的 ,而左侧有一个void*大小为 2 字节的 。int*因此,当从到发生隐式转换时,void*将会丢失一些信息

2)所有指针都保存地址。由于对于给定的机器,所有地址都具有相同的大小,因此所有指针也应该具有相同的大小是非常自然(合乎逻辑的)。

因此,我认为第二句话是正确的。


我的第一个问题是 C++ 标准对此有何规定?

我的第二个问题是,如果 C++ 标准确实允许指针具有不同的大小,那么有理由吗?我的意思是允许指针具有不同的大小对我来说似乎有点不自然(考虑到我上面解释的两点)。所以,我很确定标准委员会一定已经考虑到了这一点(指针可以有不同的大小),并且已经有理由允许指针有不同的大小。请注意,只有当标准确实允许指针具有不同的大小时,我才会问这个(第二个问题)。

c++ pointers void-pointers language-lawyer pointer-conversion

56
推荐指数
5
解决办法
8669
查看次数

适用于const字符串动态数组的类型

我一直认为这const char **x是一个正确的类型,用于动态分配的const字符串数组,如下所示:

#include <stdlib.h>

int main()
{
    const char **arr = malloc(10 * sizeof(const char *));
    const char *str = "Hello!";
    arr[0] = str;
    free(arr);
}
Run Code Online (Sandbox Code Playgroud)

但是,在使用VS2017编译此代码时,我会收到此警告free:

warning C4090: 'function': different 'const' qualifiers
Run Code Online (Sandbox Code Playgroud)

我的代码有问题吗?FWIW,当我和GCC一起编译时,即使有了,也没有任何警告-Wall -Wextra -pedantic.

c const visual-studio pointer-conversion

17
推荐指数
1
解决办法
283
查看次数

通过引用传递const指针

我很困惑,为什么以下代码无法编译

int foo(const float* &a) {
    return 0;
}
int main() {
    float* a;
    foo(a);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译器给出错误:

错误:从'float*'类型的表达式初始化'const float*&'类型的引用无效

但是当我尝试在foo中没有引用时传递,它编译正常.

我认为它应该表现出相同的行为,无论我是否通过引用.

谢谢,

c++ const reference implicit-conversion pointer-conversion

14
推荐指数
1
解决办法
1万
查看次数

从派生**转换为基础**

我正在读这篇文章,遗憾的是,我无法深入理解为什么编译器不允许从Derived**转换为Base**.此外,我已经看到这个没有提供比parashift.com的链接更多的信息.

编辑:

让我们逐行分析这个代码:

   Car   car;
   Car*  carPtr = &car;
   Car** carPtrPtr = &carPtr;
   //MyComment: Until now there is no problem!

   Vehicle** vehiclePtrPtr = carPtrPtr;  // This is an error in C++
   //MyComment: Here compiler gives me an error! And I try to understand why. 
   //MyComment: Let us consider that it was allowed. So what?? Let's go ahead!

   NuclearSubmarine  sub;
   NuclearSubmarine* subPtr = &sub;
   //MyComment: this two line are OK too!

   *vehiclePtrPtr = subPtr;

   //MyComment: the important …
Run Code Online (Sandbox Code Playgroud)

c++ inheritance pointers c++-faq pointer-conversion

13
推荐指数
2
解决办法
1708
查看次数

转换为 (void**) 是否定义明确?

假设 A 是一个结构体,并且我有一个分配内存的函数

f(size_t s, void **x)
Run Code Online (Sandbox Code Playgroud)

我调用f分配内存如下。

struct A* p;
f(sizeof(struct A), (void**)&p);
Run Code Online (Sandbox Code Playgroud)

我想知道(void**)&p这里是否有一个明确定义的铸造。我知道在 C 中,将指针强制转换为明确定义的,void*反之亦然。不过,我不确定 的情况void**。我发现以下文档指出我们不应强制转换为具有更严格对齐要求的指针。是否void**有更严格或更宽松的对齐要求?

c c++ pointers casting pointer-conversion

7
推荐指数
1
解决办法
226
查看次数

为什么 gcc 13 不显示正确的二进制表示形式?

在这里回答问题时,我做了以下例子:

#include <stdio.h>
#include <math.h>

int main (void) 
{
  float_t a = -248.75;
  printf("%f\n", a);

  unsigned char* ptr = (unsigned char*)&a;
  for(size_t i=0; i<sizeof(a); i++)
  {
    printf("%.2X ", ptr[i]);
  }
}
Run Code Online (Sandbox Code Playgroud)

在版本 13 之前的 gcc 以及 clang 的所有版本上,这给出了预期的输出(x86 小端):

-248.750000
00 C0 78 C3 
Run Code Online (Sandbox Code Playgroud)

然而,当使用 gcc 13.1 编译时,我得到无意义的输出:

-248.750000
00 00 00 00 
Run Code Online (Sandbox Code Playgroud)

进一步检查发现,罪魁祸首就是这个选项-std=c2x。如果我删除它,程序将按预期运行。

使用的编译器选项:-std=c2x -pedantic-errors -Wall -Wextra -O3 -lm. https://godbolt.org/z/4qbo74eEW

这是 gcc 中的已知错误吗?

c gcc compiler-bug pointer-conversion c23

7
推荐指数
1
解决办法
177
查看次数

指针/整数算术(un)定义的行为

我有以下功能模板:

template <class MostDerived, class HeldAs>
HeldAs* duplicate(MostDerived *original, HeldAs *held)
{
  // error checking omitted for brevity
  MostDerived *copy = new MostDerived(*original);
  std::uintptr_t distance = reinterpret_cast<std::uintptr_t>(held) - reinterpret_cast<std::uintptr_t>(original);
  HeldAs *copyHeld = reinterpret_cast<HeldAs*>(reinterpret_cast<std::uintptr_t>(copy) + distance);
  return copyHeld;
}
Run Code Online (Sandbox Code Playgroud)

目的是复制特定类型的对象,并将其与由输入相同的子对象"保持".请注意,原则上,HeldAs可能是一个模糊或不可访问的基类MostDerived,因此没有演员可以在这里提供帮助.

这是我的代码,但它可以用于我控制之外的类型(即我无法修改MostDerivedHeldAs).该函数具有以下前提条件:

  • *original 属于动态类型 MostDerived
  • HeldAs是(MostDerivedMostDerived忽略cv-qualifiation)的直接或间接基类
  • *held指的是*original其基类子对象或其中一个.

让我们假设前提条件令人满意.duplicate在这种情况下是否定义了行为?

C++ 11 [expr.reinterpret.cast]说(大胆强调我的):

4指针可以显式转换为足以容纳它的任何整数类型.映射函数是实现定义的.[ 注意:对于那些了解底层机器的寻址结构的人来说,这并不奇怪.- 注意 ] ......

5可以将整数类型或枚举类型的值显式转换为指针.转换为足够大小的整数(如果实现上存在任何此类)并返回相同指针类型的指针将具有其原始值; 指针和整数之间的映射在其他方面是实现定义的.[ 注意:除3.7.4.3中描述的情况外,这种转换的结果不是安全派生的指针值.- …

c++ gcc clang undefined-behavior pointer-conversion

5
推荐指数
1
解决办法
318
查看次数

void* ptr = &amp;func; 使用 msvc 进行编译,无需任何诊断,但 gcc 和 clang 都拒绝它

我正在使用 Stanley 的《C++ Primer》一书学习 C++。特别是,关于“指针转换”的部分说:

指向任何非常量类型的指针都可以转换为void*


读完本文后,我编写了以下程序,该程序使用 msvc 进行编译,没有任何诊断,但被 gcc 和 clang 拒绝。演示

int func()
{
    return 4;
}
int main()
{
    void* ptr = &func; //works with msvc but rejected by clang and gcc
}
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,上面的程序适用于 msvc,但 gcc 说error: invalid conversion from 'int (*)()' to 'void*'

我想知道哪个编译器在这里是正确的。请注意,我已将/permissive-flag 与 msvc 一起使用以使其符合标准。

c++ pointers function-pointers language-lawyer pointer-conversion

4
推荐指数
1
解决办法
203
查看次数

将Swift协议传递给Objective-C指针

使用XCode 10.1/Swift 4.2.

我正在尝试将符合Swift协议的对象分配给Objective-C指针.以下代码是一个最小的示例,编译和按预期工作,但它给了我以下警告:

如果分配给局部变量: Incompatible pointer types initializing 'NSObject<Animal> *__strong' with an expression of type 'id<Animal> _Nullable'

如果分配给存储的属性: Incompatible pointer types assigning to 'NSObject<Animal> *' from 'id<Animal> _Nullable'

关于如何解决这个警告而不仅仅是沉默它的任何想法?

SWIFT代码:

@objc protocol Animal {
    var name: String { get }
}

@objc class Pig: NSObject, Animal {
    var name: String = "pig"
}

@objc class Cow: NSObject, Animal {
    var name: String = "cow"
}

@objc class Farm: NSObject {
    static func getAnimal(name: String) -> Animal? {
        // return …
Run Code Online (Sandbox Code Playgroud)

objective-c compiler-warnings pointer-conversion swift swift-protocols

3
推荐指数
1
解决办法
146
查看次数

C ++:在这些情况下,reinterpret_cast是最佳选择吗?

这困扰了我很长时间:如何进行从任何东西char *到将二进制文件转储到磁盘的指针转换。

在C语言中,您甚至无需考虑。

double d = 3.14;
char *cp = (char *)&d;

// do what u would do to dump to disk
Run Code Online (Sandbox Code Playgroud)

但是,在C ++中,每个人都说C-cast不被接受,我一直在这样做:

double d = 3.14;
auto cp = reinterpret_cast<char *>(&d);
Run Code Online (Sandbox Code Playgroud)

现在这是从cppreference复制的,所以我认为这是正确的方法。

但是,我从多个消息来源读到这是UB。(例如,这个)所以我不禁要问是否有任何“ DB”方式(根据那篇文章,没有)。

我经常遇到的另一种情况是实现这样的API:

void serialize(void *buffer);
Run Code Online (Sandbox Code Playgroud)

您将在其中将很多东西转储到此缓冲区。现在,我一直在这样做:

void serialize(void *buffer) {
    int intToDump;
    float floatToDump;

    int *ip = reinterpret_cast<int *>(buffer);
    ip[0] = intToDump;

    float *fp = reinterpret_cast<float *>(&ip[1]);
    fp[0] = floatToDump;
}
Run Code Online (Sandbox Code Playgroud)

好吧,我想这也是UB。

现在,真的没有“ DB”方法可以完成这两项任务吗?我见过有人uintptr_t用来完成类似于sth的serialize任务,将指针与一起作为整数数学sizeof …

c++ reinterpret-cast pointer-conversion

3
推荐指数
1
解决办法
130
查看次数

C++指针类型的隐式转换

考虑这个案例:

int *ptr;
int offset;
ptr = <some_address>;
offset = 10;
Run Code Online (Sandbox Code Playgroud)

假设它offset是 32 位变量。ptr具有 type int*,目标体系结构是 64 位(ptr8 字节变量也是如此),offset具有 type int。计算表达式的值时会进行什么转换*(ptr + offset)?我在哪里可以在 2003 C++ 标准中阅读它?

c++ implicit-conversion pointer-conversion

2
推荐指数
1
解决办法
804
查看次数