user1829: Given a private key, I can get the uncompressed or compressed version of the public key like so.
EC_KEY* pKey = EC_KEY_new_by_curve_name(NID_secp256k1);

std::vector<unsigned char> getPubKey(EC_KEY* pKey, bool compressed) const {
    if (compressed)
        EC_KEY_set_conv_form(pKey, POINT_CONVERSION_COMPRESSED);
    else
        EC_KEY_set_conv_form(pKey, POINT_CONVERSION_UNCOMPRESSED);

    int nSize = i2o_ECPublicKey(pKey, NULL);
    std::vector<unsigned char> pubKey(nSize, 0)
    unsigned char* pBegin = &pubKey[0];
    i2o_ECPublicKey(pKey, &pBegin)
    return pubKey;
}

But how can I get the uncompressed public key from the compressed public key without knowing the private key?

user9128: If you have a compressed octet pubkey, use octet to point, then point to octet.
EC_POINT_oct2point(group, point, data, size, ctx);
EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, data, len, ctx);


user60443: You could also use the following to get an EC_POINT from a compressed key:
int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
                                             EC_POINT *p,
                                             const BIGNUM *x, int y_bit,
                                             BN_CTX *ctx);

and the following to convert the EC_POINT to an EC_KEY:
 int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub);

From EC_POINT_new documentation:

Points can also be described in terms of their compressed
  co-ordinates. For a point (x, y), for any given value for x such that
  the point is on the curve there will only ever be two possible values
  for y. Therefore a point can be set using the
  EC_POINT_set_compressed_coordinates_GFp() and
  EC_POINT_set_compressed_coordinates_GF2m() functions where x is the x
  co-ordinate and y_bit is a value 0 or 1 to identify which of the two
  possible values for y should be used.

and EC_KEY_new documentation:

The functions EC_KEY_get0_group(), EC_KEY_set_group(),
  EC_KEY_get0_private_key(), EC_KEY_set_private_key(),
  EC_KEY_get0_public_key(), and EC_KEY_set_public_key() get and set the
  EC_GROUP object, the private key, and the EC_POINT public key for the
  key respectively.


1829: <p>Given a private key, I can get the uncompressed or compressed version of the public key like so.</p>

<pre><code>EC_KEY* pKey = EC_KEY_new_by_curve_name(NID_secp256k1);

std::vector&lt;unsigned char&gt; getPubKey(EC_KEY* pKey, bool compressed) const {
    if (compressed)
        EC_KEY_set_conv_form(pKey, POINT_CONVERSION_COMPRESSED);
    else
        EC_KEY_set_conv_form(pKey, POINT_CONVERSION_UNCOMPRESSED);

    int nSize = i2o_ECPublicKey(pKey, NULL);
    std::vector&lt;unsigned char&gt; pubKey(nSize, 0)
    unsigned char* pBegin = &amp;pubKey[0];
    i2o_ECPublicKey(pKey, &amp;pBegin)
    return pubKey;
}
</code></pre>

<p>But how can I get the uncompressed public key from the compressed public key without knowing the private key?</p>
 9128: <p>If you have a compressed octet pubkey, use octet to point, then point to octet.</p>

<pre><code>EC_POINT_oct2point(group, point, data, size, ctx);
EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, data, len, ctx);
</code></pre>
 60443: <p>You could also use the following to get an <code>EC_POINT</code> from a compressed key:</p>

<pre><code>int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
                                             EC_POINT *p,
                                             const BIGNUM *x, int y_bit,
                                             BN_CTX *ctx);
</code></pre>

<p>and the following to convert the <code>EC_POINT</code> to an <code>EC_KEY</code>:</p>

<pre><code> int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub);
</code></pre>

<p>From <a href="https://www.openssl.org/docs/man1.0.2/crypto/EC_POINT_new.html" rel="nofollow noreferrer">EC_POINT_new documentation</a>:</p>

<blockquote>
  <p>Points can also be described in terms of their compressed
  co-ordinates. For a point (x, y), for any given value for x such that
  the point is on the curve there will only ever be two possible values
  for y. Therefore a point can be set using the
  EC_POINT_set_compressed_coordinates_GFp() and
  EC_POINT_set_compressed_coordinates_GF2m() functions where x is the x
  co-ordinate and y_bit is a value 0 or 1 to identify which of the two
  possible values for y should be used.</p>
</blockquote>

<p>and <a href="https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new.html" rel="nofollow noreferrer">EC_KEY_new documentation</a>:</p>

<blockquote>
  <p>The functions EC_KEY_get0_group(), EC_KEY_set_group(),
  EC_KEY_get0_private_key(), EC_KEY_set_private_key(),
  EC_KEY_get0_public_key(), and EC_KEY_set_public_key() get and set the
  EC_GROUP object, the private key, and the EC_POINT public key for the
  key respectively.</p>
</blockquote>
