casting a pointer to integer issues warning on 64bit arch

寵の児 提交于 2019-12-05 15:04:02

The PTR_ERR() macro in linux/err.h, which is where IS_ERR() is also defined, converts a pointer that's really an error code into the appropriate type (a long).

You should use something like:

if (IS_ERR(file))
    return PTR_ERR(file);

Search for existing uses of PTR_ERR() in the source and you'll see this is a common pattern.

It might be appropriate for your function to return a long rather than an int - but all error codes should be representable in an int.

You can't properly cast a pointer to a type of smaller size, period. You could do some conversion if you were sure of what that pointer stored.

For example, if you know that a pointer has only lowest 32 bits set you can just cast it and use some compiler-specific pragma to suppress the warning. Or if you want to hash the pointer for using in something like a hash table you could xor the upper 32 bits with the lower 32 bits.

This can't be decided without more knowledge of how that int is used later.

Im not sure I get how you sometimes want to return an number from errno-base.h and sometimes a pointer -- how would the receiving function be able to tell the two apart? That being equal, then on Linux GCC,

  • int is 32bit wide irrespective of whether you are on 32 or 64bit linux
  • pointers are 64 bit wide on 64 bit architectures, and 32 bite wide on 32 bit architectures
  • long are 32bit wide on 32bit architectures and 64 bit wide on 64 bit architectures.
  • long long are always 64bit wide

hence on a 64bit architecture casting a pointer to an int means that you will case a 64bit value to a 32bit value, and you can be somewhat sure that you will lose part of the 64bit information from the pointer -- and this is what the compiler warning is all about, as you point out yourself.

If you want to cast from pointer to something 'anonymous' then your choices should be either long, long long or void* -- with the void* being the most portable.

The other alternative is to record it as an offset, that is if you have a large memory area where you want to 'cast' to a 32bit integer, then convert it to something like;

  static struct mybigbuffer *globalbuffer;
   int cast2int(void*x)
   {
       return (int)(globalbuffer-(struct mybigbuffer*)x);
   }

however that is only work assuming that you know that your your memory will never exceed 2^31 records of globalbuf and that your pointers are assured to align on boundaries etc -- so unless you are 100% sure you know what you are doing, I would not recommended this either -- stick with the long or void* as the safe options.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!